Detailed software changes deprecated

This page contains detailed information about software changes.

8.55.534

Configuration

SCR-2252

Summary: New properties com.openexchange.oauth.provider.introspection.connectTimeout and com.openexchange.oauth.provider.introspection.readTimeout

Effective: 8.55.534 and later

Token introspection requests to the end-point configured via com.openexchange.oauth.provider.introspection.endpoint now time out. An end-point that never answered used to block every request presenting the same token, and any configuration reload, without limit.

  • com.openexchange.oauth.provider.introspection.connectTimeout The timeout in milliseconds for connecting to the introspection end-point. A value less than or equal to 0 (zero) is ignored and the default is used. Default 5000. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.oauth.provider.introspection.readTimeout The timeout in milliseconds for reading the response of the introspection end-point. A value less than or equal to 0 (zero) is ignored and the default is used. Default 10000. Reloadable, not config-cascade aware. No dedicated properties file.

8.55.532

Behavioral Changes

SCR-2249

Summary: Stricter limits and scope checks for several mail requests

Effective: 8.55.525 and later; also delivered in 8.55.526, 8.55.532

Several mail requests now enforce limits and checks that they skipped before:

  • mail?action=search, and mail?action=all with unseen, deleted or categoryid, honor com.openexchange.mail.mailFetchLimit. A request for more than identifiers without a range, or with a range above the limit, fails with MSG-0095 if more mails match. Requests for identifiers only and USM/EAS clients are exempt.
  • com.openexchange.mail.rateLimit applies per user across all sessions and nodes and is reserved before a mail is sent.
  • Within /multiple, requests of OAuth, app-password, personal-access-token and other restricted sessions pass the dispatcher, so their scopes are checked. Mail requests without a matching scope fail with RA-0002. The subscriptions and subscriptionSources modules are refused for such sessions with RA-0001.
  • The mail upload limits (upload_quota_per_file, upload_quota, MAX_UPLOAD_SIZE) also apply to compose attachments taken from Drive or another mail and to mails forwarded as attachment, whatever com.openexchange.mail.compose.mailstorage.eagerUploadChecksEnabled is set to.
  • mail/categories?action=train accepts at most 1000 addresses in from and re-sorts existing mails only for the addresses of that request.
  • With force_secure set to true, the default for autoconfig?action=get, the mail auto-configuration no longer queries a config server via plain HTTP.
  • mail?action=list and mail?action=thread_references honor com.openexchange.mail.mailFetchLimit as well. For list, the identifiers of all folders in a request count together. Identifier-only requests and USM/EAS clients are exempt.
  • account?action=update checks the port allowlist com.openexchange.mail.account.whitelist.ports and the host blacklist whenever an update changes the mail or transport server URL, also if it only sends a new port. Updates that keep the URL, such as a rename, are not checked.
  • The mail auto-configuration rejects responses larger than 1 MB after decompression. A broken or oversized response from a domain's config server no longer aborts the look-up; the remaining sources are tried.
  • If Drive Mail is requested when a composition space is opened, mails forwarded as attachment are checked against the Drive upload limit instead of the mail upload quotas.
  • Sieve scripts written by other clients keep a backslash followed by digits as it is, for example C:\Archiv\2023. Before, such sequences were converted like octal escapes and written back on the next change.
  • mail?action=thread_references refuses a THREAD response that lists more than 100,000 mails with MSG-0095, for every account. If size is given, a response that lists more than size plus 1,000 mails fails with IMAP-2051.
  • A Drive Mail file named in the X-OX-Shared-Attachment-Reference header of a mail is only read from, and attachments are only added to, folders the user created below their own personal folder or within the infostore trash. Only the draft's own Drive Mail folder is renamed, shared or deleted. A reference to a file in such a folder of the user's own still resolves.
  • When the IMAP server ends connections (kick, restart, failover), the user's idle cached IMAP connections are dropped at once. A reset, broken pipe or TLS failure on an established connection is reported as MSG-1035 instead of MSG-1016. A copy is no longer retried after a closed connection once issued, since a retry copied the mails twice; it fails with MSG-1016 instead.
  • A temporary login refusal no longer counts towards the failed logins that disable an external account: POP3 [IN-USE] and [SYS/TEMP] and SMTP 4xx replies to AUTH are skipped. Wrong credentials still count as before.

On 8.49 to 8.55, only the scope check within /multiple, the port allowlist check on account updates, the 1 MB limit for auto-configuration responses, the limit for THREAD responses of thread references, the restriction of Drive Mail references to the user's own attachment folders and the handling of temporary POP3 and SMTP login refusals are included.

No operator action is required.

8.55.531

Configuration

SCR-2251

Summary: Configuration option com.openexchange.oidc.jwsAlgorithm accepts several algorithms, EdDSA and HMAC

Effective: 8.55.531 and later

OpenID Connect ID tokens and logout tokens may now be signed with EdDSA or HMAC. Several signing algorithms can be accepted at once, e.g. while the OpenID Provider moves its signing key to another algorithm.

  • com.openexchange.oidc.jwsAlgorithm The JWS algorithms the OpenID Provider signs ID tokens and logout tokens with, as a comma-separated list such as RS512, EdDSA. A single value works as before. EdDSA, Ed25519 and Ed448 are verified with the provider's JWK set; HS256, HS384 and HS512 with the client secret, which needs at least 32, 48 or 64 bytes. Configure a list only after all nodes are updated: older versions reject every token while a list is set. Default RS256. Reloadable, not config-cascade aware. No dedicated properties file.

8.55.526

Behavioral Changes

SCR-2249

Summary: Stricter limits and scope checks for several mail requests

Effective: 8.55.525 and later; also delivered in 8.55.526

Several mail requests now enforce limits and checks that they skipped before:

  • mail?action=search, and mail?action=all with unseen, deleted or categoryid, honor com.openexchange.mail.mailFetchLimit. A request for more than identifiers without a range, or with a range above the limit, fails with MSG-0095 if more mails match. Requests for identifiers only and USM/EAS clients are exempt.
  • com.openexchange.mail.rateLimit applies per user across all sessions and nodes and is reserved before a mail is sent.
  • Within /multiple, requests of OAuth, app-password, personal-access-token and other restricted sessions pass the dispatcher, so their scopes are checked. Mail requests without a matching scope fail with RA-0002. The subscriptions and subscriptionSources modules are refused for such sessions with RA-0001.
  • The mail upload limits (upload_quota_per_file, upload_quota, MAX_UPLOAD_SIZE) also apply to compose attachments taken from Drive or another mail and to mails forwarded as attachment, whatever com.openexchange.mail.compose.mailstorage.eagerUploadChecksEnabled is set to.
  • mail/categories?action=train accepts at most 1000 addresses in from and re-sorts existing mails only for the addresses of that request.
  • With force_secure set to true, the default for autoconfig?action=get, the mail auto-configuration no longer queries a config server via plain HTTP.
  • mail?action=list and mail?action=thread_references honor com.openexchange.mail.mailFetchLimit as well. For list, the identifiers of all folders in a request count together. Identifier-only requests and USM/EAS clients are exempt.
  • account?action=update checks the port allowlist com.openexchange.mail.account.whitelist.ports and the host blacklist whenever an update changes the mail or transport server URL, also if it only sends a new port. Updates that keep the URL, such as a rename, are not checked.
  • The mail auto-configuration rejects responses larger than 1 MB after decompression. A broken or oversized response from a domain's config server no longer aborts the look-up; the remaining sources are tried.
  • If Drive Mail is requested when a composition space is opened, mails forwarded as attachment are checked against the Drive upload limit instead of the mail upload quotas.
  • Sieve scripts written by other clients keep a backslash followed by digits as it is, for example C:\Archiv\2023. Before, such sequences were converted like octal escapes and written back on the next change.

On 8.49 to 8.55, only the scope check within /multiple, the port allowlist check on account updates and the 1 MB limit for auto-configuration responses are included.

No operator action is required.

8.55.525

Behavioral Changes

SCR-2249

Summary: Stricter limits and scope checks for several mail requests

Effective: 8.55.525 and later

Several mail requests now enforce limits and checks that they skipped before:

  • mail?action=search, and mail?action=all with unseen, deleted or categoryid, honor com.openexchange.mail.mailFetchLimit. A request for more than identifiers without a range, or with a range above the limit, fails with MSG-0095 if more mails match. Requests for identifiers only and USM/EAS clients are exempt.
  • com.openexchange.mail.rateLimit applies per user across all sessions and nodes and is reserved before a mail is sent.
  • Within /multiple, requests of OAuth, app-password, personal-access-token and other restricted sessions pass the dispatcher, so their scopes are checked. Mail requests without a matching scope fail with RA-0002. The subscriptions and subscriptionSources modules are refused for such sessions with RA-0001.
  • The mail upload limits (upload_quota_per_file, upload_quota, MAX_UPLOAD_SIZE) also apply to compose attachments taken from Drive or another mail and to mails forwarded as attachment, whatever com.openexchange.mail.compose.mailstorage.eagerUploadChecksEnabled is set to.
  • mail/categories?action=train accepts at most 1000 addresses in from and re-sorts existing mails only for the addresses of that request.
  • With force_secure set to true, the default for autoconfig?action=get, the mail auto-configuration no longer queries a config server via plain HTTP.
  • mail?action=list and mail?action=thread_references honor com.openexchange.mail.mailFetchLimit as well. For list, the identifiers of all folders in a request count together. Identifier-only requests and USM/EAS clients are exempt.
  • account?action=update checks the port allowlist com.openexchange.mail.account.whitelist.ports and the host blacklist whenever an update changes the mail or transport server URL, also if it only sends a new port. Updates that keep the URL, such as a rename, are not checked.
  • The mail auto-configuration rejects responses larger than 1 MB after decompression. A broken or oversized response from a domain's config server no longer aborts the look-up; the remaining sources are tried.
  • If Drive Mail is requested when a composition space is opened, mails forwarded as attachment are checked against the Drive upload limit instead of the mail upload quotas.
  • Sieve scripts written by other clients keep a backslash followed by digits as it is, for example C:\Archiv\2023. Before, such sequences were converted like octal escapes and written back on the next change.

On 8.49 to 8.55, only the scope check within /multiple, the port allowlist check on account updates and the 1 MB limit for auto-configuration responses are included.

No operator action is required.

8.55.524

API - HTTP-API

SCR-1995

Summary: New Mobile API for native mail apps at /mobile/v1

Effective: 8.55.481 and later; also delivered in 8.55.524

The middleware serves a resource-oriented HTTP API for native mail apps at /mobile/v1, described by its own OpenAPI document. This release brings the foundation every operation builds on; the mail operations follow.

  • Every request carries a bearer token. A deployment signs in either with personal access tokens (oxa_…) or with the operator's identity provider, never with both; a token of the other kind is answered with 401.
  • GET /mobile/v1/auth/config needs no token and tells a client which of the two modes applies and what it needs for it.
  • Errors are application/problem+json (RFC 9457) with a stable code clients switch on, the middleware's own error code as oxCode and the request's tracking identifier as instance.
  • Every GET also answers HEAD. An unknown path is 404, a known path with another method 405 with Allow.
  • If-None-Match answers 304. The write operations that follow will answer 428 without If-Match and 412 with the current representation when it is stale.

The API answers only where com.openexchange.mobile.api.enabled is set, and it needs the OAuth provider to validate tokens. Existing endpoints are unaffected.

The server bounds how many requests a user makes per time window and how many run at once; each entry of a batch counts, the event stream does not. Beyond that, a request is answered with 429, code rate_limited and Retry-After without any effect; the client waits that long and retries. The limits are set through com.openexchange.mobile.api.rateLimit.*, com.openexchange.mobile.api.idempotency.* and com.openexchange.mobile.api.uploads.maxConcurrent. In mode idp, a token the identity provider issued to another client is answered with 401 and invalid_token unless com.openexchange.mobile.auth.idp.checkAudience is false.

The Mobile API gains GET /mobile/v1/mail/folder-changes, with which native mail apps fetch the folders created, updated and destroyed since the state of an earlier folder list, instead of reloading the whole list. GET /mobile/v1/mail/folders now returns that state at the top level. The delta embeds the created and updated folders in folders and maps former to new identifiers in renamed for accounts whose folder identifiers change on a rename. A call returns at most limit identifiers (default and maximum 500) and sets hasMore when more follow. The state covers the accounts, subscribedOnly and, if the list asked for them, the counts of the list it came from. A state that is unknown, expired or whose account is gone is answered with 410 and code cannot_calculate_changes; the client reloads the list. The middleware keeps a snapshot per state in Redis, at most 50 and 1.5 MiB per user for 7 days after the last use; a list of more than about 5000 folders gets no state. IMAP and JMAP accounts are supported.

A failing key-value store is answered with 503 and Retry-After instead of 500. While the store cannot be reached, an operation that requires an Idempotency-Key, such as sending, performs nothing and is answered the same way; one with an optional key runs without the protection. GET /mobile/v1/mail/folders returns no state while an account could not be read; an account without mail access, e.g. in state secret_unavailable, counts as read without folders. At the snapshot limit, superseded states are dropped first. For JMAP accounts, a delta with counts reports every change for all folders of the account.

Clients send Accept: application/problem+json together with application/json on every request; the problem body is guaranteed only when Accept allows it. A 401 may carry more than one WWW-Authenticate challenge; clients evaluate the Bearer challenge and ignore the others. The middleware itself keeps sending the problem body whatever Accept says, with a single challenge, so a client that follows both rules behaves the same whether or not an authentication layer checks tokens in front of the middleware.

POST /mobile/v1/mail/folders/{folderId}/empty removes all messages of a folder in one call: they go to the trash unless the folder is in the trash, permanent=true is given or the user deletes for good. It requires Idempotency-Key. POST /mobile/v1/mail/folders/{folderId}/mark-read marks all messages of a folder as read. GET /mobile/v1/mail/accounts/{accountId}/quota tells how much of its storage and message quota a mail account uses; a quota the mailbox does not have is left out.

With categoryId, mark-read marks only the messages of that inbox category, the same ones listMessages with categoryId lists; it is accepted for the inbox of the primary account only.

Responses to calls with a token carry RateLimit-Policy and RateLimit (IETF draft): the size of the user's request budget and its window, the requests left and the seconds until the budget is full again. The budget is a token bucket: a burst of com.openexchange.mobile.api.rateLimit.requests requests, then an even refill over com.openexchange.mobile.api.rateLimit.windowSeconds. Inside a batch each entry carries the headers.

8.55.511

Configuration

SCR-2238

Summary: Reloadable Redis command timeout and connection pool settings, and new degraded mode configuration options

Effective: 8.55.511 and later

The Redis command timeout and the connection pool settings now take effect on a configuration reload, without restarting the middleware. This also applies to the instance-specific variants (com.openexchange.redis.<instance>.…).

  • com.openexchange.redis.commandTimeoutMillis: The timeout for a Redis command in milliseconds; a reload applies it to established connections as well. Default 5000. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.connection.pool.maxTotal: The maximum number of connections in the pool. Only applies to pool mode dedicated. Default 100. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.connection.pool.maxIdle: The maximum number of idle connections in the pool. Only applies to pool mode dedicated. Default 100. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.connection.pool.minIdle: The minimum number of idle connections kept in the pool. Only applies to pool mode dedicated. Default 0. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.connection.pool.maxWaitSeconds: How long to wait for a free pooled connection, in seconds. Only applies to pool mode dedicated. Default 2. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.connection.pool.minIdleSeconds: The idle time in seconds after which a pooled connection may be evicted. Default 60. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.connection.pool.cleanerRunSeconds: The interval in seconds between two runs of the pool cleaner. Default 10. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.connection.pool.invalidateOnCommandTimeout: Whether a pooled connection that ran into a command timeout is closed instead of returned to the pool. Only applies to pool mode dedicated. Default false. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.connection.pool.newConnectionIfWaitExceeded: Whether to open a new connection once waiting for a free pooled connection exceeds com.openexchange.redis.connection.pool.maxWaitSeconds. Only applies to pool mode dedicated. Default true. Reloadable, not config-cascade aware. File: redis.properties.

In addition, a degraded mode for the Redis connector was introduced: in the degraded state the failure thresholds of both circuit breakers are multiplied by a factor and their open delays are shortened, so that sporadic failures - typically packet loss towards the Redis end-point - do not open them over and over again. The instance-specific variants (com.openexchange.redis.<instance>.degraded.…) exist as well.

  • com.openexchange.redis.degraded.mode: The degraded mode: off, monitor (transitions are only logged and counted), auto (the connector enters and leaves the degraded state by itself) or forced (permanently degraded). Default "off". Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.degraded.failureThreshold: The number of command timeouts or connect failures within the observation window that lets mode auto enter the degraded state. Default 5. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.degraded.windowSeconds: The observation window in seconds the failures are counted in. Default 60. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.degraded.minDurationSeconds: The minimum time in seconds the connector stays degraded before a clean observation window lets it return to normal. Default 120. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.degraded.maxDurationSeconds: The maximum time in seconds the connector stays degraded in one stretch; once exceeded it returns to normal and re-evaluates. Default 900. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.degraded.breaker.failureThresholdFactor: The factor applied to the failure thresholds and failure executions of both circuit breakers while degraded. Default 4. Reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.degraded.breaker.delayMillis: The delay in milliseconds both circuit breakers wait in open state while degraded, replacing their configured delays. Default 2000. Reloadable, not config-cascade aware. File: redis.properties.

8.55.498

Changed defaults

SCR-2216

Summary: Up to 512 carrier threads for virtual threads by default

Effective: 8.55.495 and later

Along with -Djdk.virtualThreadScheduler.parallelism=256 (SCR-1998), the middleware now sets -Djdk.virtualThreadScheduler.maxPoolSize=512, the most carrier threads the JVM may run, including those it adds while virtual threads wait in a host name lookup, an fsync or a file lock. The JVM default of max(parallelism, 256) left none to add at 256, so slow DNS lookups could block every carrier.

The option is not added if a JAVA_OPTS_* value sets the parallelism or the maximum pool size. With a parallelism above 256, also set -Djdk.virtualThreadScheduler.maxPoolSize above it.

8.55.497

3rd Party Libraries/License Change

SCR-2213

Summary: Upgraded third-party libraries to their latest patch or minor release

Effective: 8.55.497 and later

Upgraded third-party libraries to their latest patch or minor release. No API or configuration change; no operator action is required.

  • AWS SDK for Java from 2.57.6 to 2.57.8, embedded in software.amazon.awssdk.
  • Jackson 3 (core, databind, dataformat-yaml) from 3.2.3 to 3.2.4, embedded in io.fabric8.kubernetes.

8.55.496

Changed defaults

SCR-2217

Summary: Changed the default carrier threads for virtual threads to scale with the CPUs

Effective: 8.55.496 and later

The container entrypoint and the oxscripts now default -Djdk.virtualThreadScheduler.parallelism to four carrier threads per CPU, at least 64, instead of a static 256. A static 256 raised the load average and CPU time of small nodes during bursts of work, while the protection against the class-loading hang of SCR-1998 does not need more. CPUs are counted as the JVM counts them: those the process may run on, capped by the CPU quota of its cgroup.

-Djdk.virtualThreadScheduler.maxPoolSize now defaults to the parallelism plus 256 instead of a static 512, keeping the headroom of SCR-2216 at any parallelism. It is now also derived from a parallelism that a JAVA_OPTS_* value or JAVA_XTRAOPTS sets. No operator action is required; both options yield to configured values.

8.55.495

Changed defaults

SCR-1998

Summary: More carrier threads for virtual threads by default

Effective: 8.55.495 and later

The middleware now starts with -Djdk.virtualThreadScheduler.parallelism=256, the number of carrier threads its virtual threads run on, unless a JAVA_OPTS_* value already sets it. A virtual thread that loads a class is pinned to its carrier: with no more carriers than CPU cores, requests loading the same class at once could pin them all while the holder of a class loader lock waited for a carrier, and the middleware stopped answering. Carrier threads are ordinary platform threads, and idle ones cost little. Set the option in JAVA_OPTS_OTHER or in ox-scriptconf.sh to choose another value.

Along with it, the middleware sets -Djdk.virtualThreadScheduler.maxPoolSize=512, the most carrier threads the JVM may run, including those it adds while virtual threads wait in a host name lookup, an fsync or a file lock. The JVM default of max(parallelism, 256) left none to add at 256, so slow DNS lookups could block every carrier. The option is not added if a JAVA_OPTS_* value sets the parallelism or the maximum pool size; with a parallelism above 256, also set -Djdk.virtualThreadScheduler.maxPoolSize above it.

8.55.484

API - HTTP-API

SCR-2171

Summary: Address Books of Shared Accounts in the HTTP API

Effective: applies to the 8.55 release line

Users holding a contacts permission for a shared account get its address books through the addressbooks module and folders of content type addressdata; the legacy contacts module does not support them.

  • Each shared account is a contacts account con://<n>; its folders are the account's private address books and its contacts Trash folder (con://<n>/<id>). They keep their type (1, Trash 16), are listed below the private root folder and carry the new folder field com.openexchange.contacts.provider (column 3303) with value sharedaccount.
  • The account's default address book is announced read-only in the io.ox/core JSlob under sharedaccount/<account id>/folder/addressbooks.
  • sharedaccount?action=all|get report moduleConfigurations.contacts; subscribed, usedForSync and usedInPicker of these folders are kept per user under userSettings.contacts.
  • Permission levels map to folder permissions as for calendars; contacts and their attachments are written as the shared account.

Purely additive. See the HTTP API documentation for further details.

SCR-1958

Summary: New Attribute sentCopyToGranter for Deputy Permissions to Put a Copy of Mails a Deputy Sends into the Granting User's Sent Folder

Effective: applies to the 8.55 release line

The DeputyPermission and GrantedDeputyPermission objects of the deputy module carry the new optional boolean attribute sentCopyToGranter. If set, the granting user gets a copy of the mails the deputy sends for them, on their behalf or as them, in their own standard Sent folder, marked as read and only once; whether a mail gets a copy is decided each time the deputy sends, and SCR-1956 lists the mails that get no copy. The middleware puts the copy there through administrative mail access; the copy gives the deputy no additional permission.

  • PUT /appsuite/api/deputy?action=new and ?action=update accept the attribute; on update an absent attribute keeps the current value, unless the update withdraws both sendOnBehalfOf and sendAs. GET ?action=all, ?action=get and ?action=reverse return it as true where granted and omit it otherwise; ?action=reverse also omits it while com.openexchange.deputy.sentCopyToGranterEnabled is false for the granting user.
  • It requires sendOnBehalfOf or sendAs (see SCR-2144), otherwise the request fails with DEPUTY-0017, unless it is an update that passes the stored value back unchanged: withdrawing both then withdraws it as well, as it does for SCIM, which always passes the stored value back. Switching between them keeps it, and so does a grant of sendAs that acts as sendOnBehalfOf while com.openexchange.deputy.sendAsEnabled is disabled (see SCR-2143).
  • Granting it fails with DEPUTY-0018 if none of the strategies in com.openexchange.mail.admin.strategies applies to the granting user (doveadm only where com.openexchange.deputy.sentCopyToGranterDoveAdmEnabled is set), and, through the HTTP API, with DEPUTY-0019 while com.openexchange.deputy.sentCopyToGranterEnabled is false for the granting user (passing back an already stored value unchanged still works), which SCIM, as administrative provisioning, is not subject to; clients should offer it only where the capability deputy_sent_copy is granted (see SCR-1956).
  • A value that is no boolean is rejected with SVL-0010, as for sendOnBehalfOf and sendAs.
  • The SCIM resource Deputies carries the same boolean attribute sentCopyToGranter; a PUT that leaves it out keeps the stored value, unless the update withdraws both sendOnBehalfOf and sendAs, a PATCH that removes it sets it to false. Asking for it where DEPUTY-0018 applies is answered with HTTP status 400 (invalidValue). Since every deputy resource now carries it, its meta.version (ETag) changes with this update, as described for sendAs in SCR-2147.

Apart from the SCIM ETag, the change only adds the attribute: requests without it behave as before. See the API documentation and the feature documentation for further details.

API - RMI

SCR-2173

Summary: Contacts Permission Level in the RMI, gRPC, CLT and SCIM Provisioning of Shared Accounts

Effective: applies to the 8.55 release line

The provisioning of shared accounts takes and reports the permission level for the address books of a shared account, next to the calendar and mail levels. As for these (see SCR-2167), an omitted level, or one without permission level, means the configured default com.openexchange.sharedaccount.contacts.defaultPermissionSet applies.

  • RMI: OXSharedAccountInterface.createSharedAccountPermissions(..., calendarConfiguration, contactsConfiguration, mailConfiguration, ...); SharedAccountPermissions and SharedAccountPermissionsOnSet gain contactsConfig. The previous signature remains.
  • gRPC: contacts_config in SharedAccountPermissions, CreateSharedAccountPermissionsRequest and SharedAccountPermissionsOnSet.
  • CLT: createsharedaccountpermissions -K / --contactspermissionlevel; the list tools print a ContactsConfig column.
  • SCIM: attribute contacts in the permissions of the SharedAccount resource.
  • REST: moduleConfigurations.contacts of a shared account, with moduleAccountId con://<n>.

Existing calls are unaffected.

SCR-1960

Summary: New Field sentCopyToGranter in the Deputy Permission Data Objects of the Administrative RMI and gRPC Interfaces

Effective: applies to the 8.55 release line

The RMI data objects com.openexchange.admin.rmi.dataobjects.DeputyPermission (and thereby ActiveDeputyPermission) and DeputyPermissionDescription carry the new boolean field sentCopyToGranter (isSentCopyToGranter and setSentCopyToGranter): if set, the granting user gets a copy of the mails the deputy sends for them, on their behalf or as them, in their standard Sent folder. The description object tracks it with the companion flag isSentCopyToGranterSet, so an absent field keeps the current value on update, unless the update withdraws both sendOnBehalfOf and sendAs. The shared account interface carries the field along wherever it converts deputy permissions, e.g. when it restores the deputy permissions it revoked because converting a user into a shared account failed; a deputy permission whose copy cannot be granted at that moment (DEPUTY-0018) is restored without it, as is one whose copy was left stored without a right to send (see SCR-1957).

The gRPC provisioning API mirrors it in deputy.proto: DeputyPermission.sent_copy_to_granter (field 9) and the description pair sentCopyToGranter (17) with SentCopyToGranterSet (18). It goes through the same RMI service as the SOAP interface, so semantics and validation are the same, see SCR-1959.

The change only adds fields: the existing gRPC field numbers stay as they are, and an RMI or gRPC client that does not set the field keeps the stored value on update, unless the update withdraws both sendOnBehalfOf and sendAs. See the feature documentation for further details.

API - SOAP

SCR-2172

Summary: New Element contactsConfig in the SOAP Service for Shared Accounts

Effective: applies to the 8.55 release line

The SOAP service http://soap.admin.openexchange.com/OXSharedAccountService takes and reports the permission level for the address books of a shared account, next to calendarConfig and mailConfig. As for these (see SCR-2167), an omitted contactsConfig, or one without permissionLevel, means the configured default com.openexchange.sharedaccount.contacts.defaultPermissionSet applies.

  • New type ContactsConfiguration with the element permissionLevel (none, viewer, editor, author or admin).
  • New optional element contactsConfig in createSharedAccountPermissions, as the last element after auth.
  • New optional element contactsConfig in SharedAccountPermissions, as returned by listSharedAccountPermissions, listSharedAccountPermissionsForSharedAccount and getSharedAccountPermissions.
  • New optional element contactsConfig in SharedAccountPermissionsForContext, as taken by setSharedAccountPermissions.
<soap:createSharedAccountPermissions>
  <soap:ctx><xsd:id>2</xsd:id></soap:ctx>
  <soap:users><xsd:id>4</xsd:id></soap:users>
  <soap:sharedAccountCtx><xsd:id>1</xsd:id></soap:sharedAccountCtx>
  <soap:sharedAccount><xsd:name>support</xsd:name></soap:sharedAccount>
  <soap:auth><xsd:login>oxadmin</xsd:login><xsd:password>secret</xsd:password></soap:auth>
  <soap:contactsConfig><xsd:permissionLevel>viewer</xsd:permissionLevel></soap:contactsConfig>
</soap:createSharedAccountPermissions>

Existing requests are unaffected. See the feature documentation for further examples.

SCR-1959

Summary: New Element sentCopyToGranter in the Deputy Permissions of the OXDeputyPermissionsService

Effective: applies to the 8.55 release line

The data objects DeputyPermission and ActiveDeputyPermission of the OXDeputyPermissionsService carry the new optional, nillable boolean element sentCopyToGranter: if set, the granting user gets a copy of the mails the deputy sends for them, on their behalf or as them, in their standard Sent folder (see SCR-1958 for the semantics). In both complex types the element is appended at the end of the sequence, after sendAs (see SCR-2145). The grant and update operations accept it; get and list return it. On update an absent element keeps the current value, unless the update withdraws both sendOnBehalfOf and sendAs.

It requires sendOnBehalfOf or sendAs, otherwise the request fails with DEPUTY-0017, unless it is an update that passes the stored value back unchanged (see SCR-1958); granting it fails with DEPUTY-0018 if none of the strategies in com.openexchange.mail.admin.strategies applies to the granting user, doveadm only where com.openexchange.deputy.sentCopyToGranterDoveAdmEnabled is set (see SCR-1956). Requests without the element behave as before; responses carry the new element, which clients that validate strictly against an older WSDL do not expect.

<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:Body>
    <soap:grant>
      <soap:deputyPermission>
        <xsd:userId>7</xsd:userId>
        <xsd:sendOnBehalfOf>true</xsd:sendOnBehalfOf>
        <xsd:modulePermissions>
          <xsd:moduleId>mail</xsd:moduleId>
          <xsd:admin>false</xsd:admin>
          <xsd:folderPermission>2</xsd:folderPermission>
          <xsd:readPermission>4</xsd:readPermission>
          <xsd:writePermission>0</xsd:writePermission>
          <xsd:deletePermission>0</xsd:deletePermission>
        </xsd:modulePermissions>
        <xsd:sentCopyToGranter>true</xsd:sentCopyToGranter>
      </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>

See the feature documentation for further details.

Behavioral Changes

SCR-2032

Summary: Distributed files require a token per file

Effective: applies to the 8.55 release line

The servlet at /dfm/distributedFiles, through which nodes fetch files from each other, requires the token of the requested file: in the header X-OX-DFM-Token, or for GET in the query parameter token. A request without it is answered with status 404. Nodes pass the token on their own; no admin action. During a rolling upgrade a node not yet upgraded cannot fetch files from an upgraded node, which affects preview downloads, inline images of the PDF export and job results until all nodes are upgraded. A node announces itself with the IP address from the environment variable POD_IP, if set, instead of its host name.

Changed defaults

SCR-2140

Summary: Changed default of com.openexchange.groupware.update.background.idleMillis

Effective: applies to the 8.55 release line

The schema lock of background update tasks now expires like the lock of blocking update tasks.

  • com.openexchange.groupware.update.background.idleMillis A background update lock that has not been refreshed for this many milliseconds counts as left behind, and another node may run the remaining background update tasks of that schema. Before, a node that died while running them kept the schema locked until an admin removed the lock. Keep the value above com.openexchange.groupware.update.refreshIntervalMillis (20000); 0 restores the old behavior. Default 0 → 60000. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2057

Summary: No write scope in the default scopes of a signed-in access token

Effective: applies to the 8.55 release line

The default of com.openexchange.accesstoken.signin.defaultScopes changes from read_mail,write_mail,read_contacts to read_mail,read_contacts, so a client that signs in through login?action=accessToken without naming scopes gets no write scope. A client that needs one names it in scopes. The Mobile API keeps its defaults through com.openexchange.mobile.auth.token.scopes. Deployments that rely on the old default set the property to it.

Configuration

SCR-2169

Summary: New Property com.openexchange.sharedaccount.contacts.defaultPermissionSet

Effective: applies to the 8.55 release line

Shared accounts now give access to their address books. The new lean property com.openexchange.sharedaccount.contacts.defaultPermissionSet is the contacts permission set of every user holding a permission for a shared account, also of permissions without a contacts level of their own, the counterpart of com.openexchange.sharedaccount.calendar.defaultPermissionSet. It defaults to none, is reloadable and config-cascade aware. Explicitly granted levels can only raise it.

Permissions granted before the update get no contacts level of their own (see SCR-2170). With the default none, nobody sees the address books of an existing shared account until this property is raised or a contacts level is provisioned.

See the property documentation and the feature documentation for further details.

SCR-2080

Summary: New configuration option to switch off single MCP tools

Effective: applies to the 8.55 release line

This option lets an administrator switch off single tools of the MCP server /mcp.

  • com.openexchange.mcp.tools.disabled Comma-separated names of MCP tools that are switched off. A tool switched off is neither listed by tools/list nor callable; a call is answered as for a tool that does not exist. Its resource is not served either: mail_get covers ox:///mail/{folder}/{id}, mail_attachment_get the attachments, file_get ox:///files/{id}. Prompts that need it are no longer listed. briefing_get reads its sections on its own; switch it off too to keep a module out of the briefing. Default empty. Reloadable, config-cascade aware. No dedicated properties file.

SCR-2058

Summary: New configuration option for the default scopes of the Mobile API

Effective: applies to the 8.55 release line

Tokens from POST /mobile/v1/auth/token get their default scopes from this option instead of com.openexchange.accesstoken.signin.defaultScopes.

  • com.openexchange.mobile.auth.token.scopes Comma-separated scopes a token from POST /mobile/v1/auth/token gets when the app names none; scopes the user cannot grant are left out. Default read_mail,write_mail,read_contacts. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2031

Summary: New configuration options for the AJAX job queue

Effective: applies to the 8.55 release line

The AJAX job queue keeps the state and the result of a job in Redis, so that every node answers jobs requests for it and long-running requests no longer need sticky routing. If the node executing a job is gone, the job is answered with error JOB-0005.

  • com.openexchange.jobqueue.maxResultSize The maximum size in bytes of a job result that is kept in Redis. A bigger result is kept in an encrypted file on the node that executed the job, from where the other nodes fetch it. A value less than or equal to 0 (zero) means unlimited. Default 1048576. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.jobqueue.maxDistributedResultSize The maximum size in bytes of a job result that nodes other than the executing one serve. A bigger result is served by the executing node only; other nodes answer with error JOB-0006. A value less than or equal to 0 (zero) means unlimited. Default 67108864. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-1956

Summary: New Capability deputy_sent_copy and Properties for the Copy of Mails a Deputy Sends for the Granting User

Effective: applies to the 8.55 release line

In order to let a granting user find a copy of the mails a deputy sends for them, on their behalf or as them, in their own standard Sent folder, deputy permissions get the new option sentCopyToGranter (see SCR-1958). The middleware puts the copy there through administrative mail access; the copy gives the deputy no additional permission.

  • The new capability deputy_sent_copy tells clients whether a user may grant the option. It is granted while deputy permissions are available to the user (capability deputy) and one of the strategies in com.openexchange.mail.admin.strategies (see SCR-2023) applies to the user; a token that a provisioning request brings along does not count. With the strategy token, the capability only checks that a token is kept for the user, not that it can still be used. It is never granted to guests. Whether a mail gets a copy is decided each time the deputy sends.
  • The new property com.openexchange.deputy.sentCopyToGranterEnabled (default true, reloadable, config-cascade-aware) switches the copy on or off for the granting user. While it is false, the capability is not offered, granting the option is rejected with DEPUTY-0019 except through administrative provisioning (passing back an already stored value unchanged still works), and no copy is made; stored grants are kept and take effect again once it is true.
  • The new property com.openexchange.deputy.sentCopyToGranterDoveAdmEnabled (default false, reloadable, config-cascade-aware) decides for the granting user whether the strategy doveadm counts for the copy. DoveAdm copies the mail from the deputy's Sent folder, which needs both mailboxes on the same Dovecot instance. While the property is false, the capability, granting the option and the copy only consider the other strategies; if none of them applies, granting the option is rejected with DEPUTY-0018.
  • The existing property com.openexchange.deputy.provider.imap.doveadm.personalNamespace is now also read for the copy, whatever strategy applies, in the scope of the granting user, if no Sent folder full name is stored with the granting user's primary mail account. com.openexchange.deputy.provider.imap.doveadm.sharedNamespace and com.openexchange.deputy.provider.imap.doveadm.publicNamespace are read for every copy, where set: no copy goes into a folder below them, even if the granting user stored such a folder as their Sent folder; this is logged with level WARN.
  • The copy contains the Bcc recipients of the mail, so the granting user sees whom the deputy sent a blind copy to. A copy the mail server refuses is not made.
  • If com.openexchange.mail.noCopyIntoStandardSentFolder is set to true for the deputy, no copy is made; granting the option is not rejected in that case.
  • No copy is made for mails sent as raw MIME (mail?action=new with PUT), resent (mail?action=resend) or bounced (mail?action=bounce), for mails the calendar sends for the granting user, such as invitations, changes and cancellations a deputy sends on their behalf, and for mails sent through an account other than the deputy's primary mail account. Nor is one made if the granting user found for the From address belongs to another context and another user who appointed the deputy has the same address; this is logged with level WARN. The mail itself is sent in all these cases.
  • With the strategy doveadm, where enabled, the copy is taken from the deputy's Sent folder: if the deputy chose not to keep copies of sent mails, the mail is put there for the copy and removed once it is copied; it stays there if no copy is made, if the copy or the removal fails for good, or if the deputy's session has ended by then, as for a scheduled mail.

The copy is made in the background after the send. See the feature documentation for the strategies, the retries, the logging and all cases without a copy.

Database

SCR-2170

Summary: Existing Shared Account Permissions Get a Contacts Account

Effective: applies to the 8.55 release line

Update Task com.openexchange.sharedaccount.storage.rdb.groupware.SharedAccountAddContactsAccountTask

Each shared account permission carries a contacts account, whose identifier con://<n> is part of the folder identifiers of the shared account's address books. The update task adds one to every row of sharedaccount_permissions whose configuration has no contacts entry, without a contacts level of its own, so com.openexchange.sharedaccount.contacts.defaultPermissionSet applies (see SCR-2169). No table changes; rows that already have a contacts entry are skipped. The cached permissions (cache module sacPrms) move to version 2.

Note for operators: do not create shared account permissions until all nodes run the update, since a node of the previous version creates them without a contacts account. Changes made through setSharedAccountPermissions keep the contacts entry from 8.54 on (see SCR-2167).

SCR-1957

Summary: New Column sentCopyToGranter in Table deputy for the Copy of Mails a Deputy Sends for the Granting User

Effective: applies to the 8.55 release line

Update Task com.openexchange.deputy.impl.groupware.DeputyStorageAddSentCopyToGranterColumnTask

The table deputy gets the new column sentCopyToGranter. It tells whether the granting user gets a copy of the mails the deputy sends for them in their standard Sent folder (see SCR-1956).

ALTER TABLE deputy ADD COLUMN sentCopyToGranter TINYINT(1) NOT NULL DEFAULT 0;

Fresh schemas: com.openexchange.deputy.impl.groupware.DeputyStorageCreateTableService. Existing schemas: com.openexchange.deputy.impl.groupware.DeputyStorageAddSentCopyToGranterColumnTask (idempotent, depending on DeputyStorageCreateTableTask). Existing deputy permissions get the value 0, so their behavior does not change.

The previous version does not know the column, so during a rolling upgrade nodes of that version make no copy of the mails sent through them, a deputy permission they re-create (com.openexchange.deputy.preferRecreateInsteadOfUpdate) loses it, and a right to send they withdraw leaves sentCopyToGranter stored. Nodes of this version treat such a stored copy as withdrawn: they neither make nor list it, and a right to send granted again through them does not bring it back; one granted again through a node of the previous version does, without that node showing it. Grant sentCopyToGranter only once all nodes run this version.

Packaging/Bundles

SCR-2174

Summary: New Bundle com.openexchange.mail.deputy for the Copy of Mails Sent by Deputies

Effective: applies to the 8.55 release line

The package open-xchange-deputy ships the new bundle com.openexchange.mail.deputy. It puts the copy of the mails a deputy sends for a granting user into that user's standard Sent folder, see SCR-1956.

SCR-2168

Summary: New Bundle com.openexchange.contact.provider.sharedaccount for the Address Books of Shared Accounts

Effective: applies to the 8.55 release line

The package open-xchange-sharedaccount ships the new bundle com.openexchange.contact.provider.sharedaccount. It provides the contacts provider sharedaccount, which offers the address books of a shared account to the users holding a permission for it, as com.openexchange.chronos.provider.sharedaccount does for its calendars.

8.55.481

3rd Party Libraries/License Change

SCR-2208

Summary: Patched re2j 1.8 so that compiling a case-insensitive pattern holding certain Cyrillic letters returns

Effective: 8.55.481 and later

The bundle com.google.re2j now ships as re2j-1.8-ox1-custom.jar, with Unicode.simpleFold patched as proposed upstream in google/re2j#213. Before, Pattern.compile never returned for a case-insensitive pattern holding one of the characters U+1C80 to U+1C88, which kept the calling thread busy. These characters now match only themselves case-insensitively; all other case folding is unchanged.

SCR-2119

Summary: Upgraded forty-two third-party libraries to their latest patch or minor release

Effective: 8.55.481 and later

Upgraded forty-two third-party libraries to their latest patch or minor release. No API or configuration change; no operator action is required.

  • Google Calendar API client from v3-rev20260708-2.0.0 to v3-rev20260925-2.0.0, embedded in com.google.api.client.
  • snappy-java from 1.1.10.8 to 1.1.10.12 in the target platform.
  • javax.inject from the 2.4.0-b10 pre-release to the final 2.4.0 release of org.glassfish.hk2.external in the target platform.
  • Jetty from 12.1.13 to 12.1.14, embedded in com.openexchange.http.jetty.
  • GlassFish CORBA OMG API from 5.0.2 to 5.0.3 in the target platform (glassfish-corba-omgapi-5.0.3-custom.jar).
  • TwelveMonkeys ImageIO from 3.15.2 to 3.15.3, embedded in com.openexchange.imagetransformation.java.
  • Netty from 4.2.18.Final to 4.2.19.Final, embedded in io.netty.
  • Apache Jackrabbit WebDAV from 2.22.4 to 2.22.5 in the target platform (jackrabbit-webdav-2.22.5-custom.jar).
  • AWS SDK for Java from 2.55.11 to 2.57.6, embedded in software.amazon.awssdk.
  • Amazon S3 Encryption Client from 4.0.2 to 4.0.3, embedded in software.amazon.awssdk.
  • gRPC from 1.84.0 to 1.85.1, embedded in the gRPC framework libraries and com.google.api.client.
  • libphonenumber from 9.0.40 to 9.0.42, embedded in com.openexchange.sms.
  • Apache CXF from 4.2.3 to 4.2.4, embedded in com.openexchange.soap.common; this also moves XmlSchema from 2.3.2 to 2.3.3.
  • Kotlin standard library from 2.4.20 to 2.4.21 in the target platform.
  • Yubico WebAuthn server library from 2.10.0 to 2.10.1, embedded in com.openexchange.webauthn.
  • ASM from 9.10.1 to 9.11.1 in the target platform.
  • Stax2 API from 4.3.1 to 4.3.2 in the target platform.
  • Apache HttpClient 5 from 5.6.4 to 5.6.5 in the target platform (httpclient5-5.6.5-custom.jar), and its cache module embedded in com.openexchange.saml.
  • Gmail API client from v1-rev20260727-2.0.0 to v1-rev20261005-2.0.0, embedded in com.google.api.client.
  • Caffeine from 3.3.0 to 3.3.1, embedded in com.google.guava.
  • Lettuce from 7.8.0 to 7.9.0, embedded in io.lettuce; this also moves redis-authx-core from 0.1.1-beta2 to 0.2.0.
  • Apache Cassandra Java Driver from 4.19.3 to 4.19.4, embedded in com.openexchange.nosql.cassandra.
  • Box Java SDK from 10.19.0 to 10.20.0, embedded in com.openexchange.file.storage.boxcom.
  • Prometheus metrics library from 1.9.0 to 1.10.0, embedded in com.openexchange.metrics.micrometer.
  • Apache Kafka client from 4.3.1 to 4.4.0 in the target platform (org.apache.servicemix.bundles.kafka-clients-4.4.0-custom.jar).
  • Jackson from 2.22.3 to 2.22.4 in the target platform. The Jakarta REST providers (jackson-jakarta-rs-*) now come from upstream again, since 2.22.4 itself accepts Jakarta REST 4.

  • jOOX from 2.0.1 to 2.0.2, embedded in com.openexchange.xml.

  • MySQL Connector/J from 26.7.0 to 26.10.0 in the target platform and in com.openexchange.datamining.

  • metadata-extractor from 2.21.0 to 2.22.0, embedded in com.drew; it limits container nesting in QuickTime/MP4/HEIF files and avoids a stack overflow on long TIFF IFD chains.

  • OkHttp from 5.5.0 to 5.5.1, embedded in com.squareup.okhttp3; it blocks the compromised eMudhra intermediate certificates.

  • Micrometer from 1.17.1 to 1.17.2, embedded in com.openexchange.metrics.micrometer.

  • Reactor Core from 3.8.7 to 3.8.8, embedded in io.lettuce.

  • Spring Framework (core, beans) from 7.0.9 to 7.0.10, embedded in com.openexchange.xml.

  • Google API Client from 2.9.1 to 2.9.2, embedded in com.google.api.client; its bundled trust store now carries Google's current root certificates.

  • Jolokia from 2.6.3 to 2.6.4, embedded in com.openexchange.jolokia. Jolokia now accepts JSON POST requests only with the content type application/json or without one, and rejects application/json with a charset parameter with HTTP 400. GET requests are unchanged. Reported upstream as jolokia#1071.

  • Gson from 2.14.0 to 2.15.0 in the target platform. Gson now deserializes untyped JSON objects into a LinkedHashMap instead of its own LinkedTreeMap (same iteration order), and reads an InetAddress only from a numeric IP address.

  • dnsjava from 3.6.5 to 3.7.0 in the target platform. It fixes five security advisories, among them unbounded pre-allocation from DNS header count fields and a TSIG MAC comparison that was not constant-time.

  • Logback from 1.6.5 to 1.6.6 in the target platform and the command-line tools. Its socket receiver now rejects crafted serialized exception graphs that looped forever, and FileNamePattern escapes regular-expression characters in file names.

  • Google Auth Library from 1.54.0 to 1.55.0, embedded in com.google.api.client and com.google.firebase.

  • Google API Common from 2.70.0 to 2.71.0, embedded in com.google.api.client.

  • Joda-Time from 2.15.0 to 2.15.1 in the target platform, with time zone data 2026f.

  • Apache Tika core from 4.1.0 to 4.2.0, embedded in com.openexchange.tika.util. It now also embeds Apache Commons Secure XML 1.1.0, which Tika uses to parse its MIME type definitions.

On 8.54, only the Apache CXF 4.2.4, Guava 33.7.2, Jackson 2.22.4 and Logback 1.6.5 upgrades are included.

SCR-2097

Summary: Upgraded Grizzly to 5.0.3

Effective: 8.55.481 and later

Upgraded Grizzly from 5.0.2 to 5.0.3, embedded in com.openexchange.http.grizzly. With HTTP/2 enabled (com.openexchange.http.grizzly.http2.enabled), large responses are no longer cut off and later requests on the same listener no longer stall until the write timeout. No API or configuration change; no operator action is required.

SCR-2089

Summary: Upgraded the Yubico WebAuthn server library to 2.10.0

Effective: 8.55.481 and later

Upgraded the Yubico WebAuthn server library (webauthn-server-core, yubico-util) from 2.9.0 to 2.10.0, embedded in com.openexchange.webauthn. No API or configuration change; no operator action is required.

SCR-2081

Summary: Upgraded Jersey and Joda-Time to their latest patch or minor release

Effective: 8.55.481 and later

Upgraded Jersey and Joda-Time to their latest patch or minor release. No API or configuration change; no operator action is required.

  • Jersey from 4.0.2 to 4.0.3 in the target platform, matching HK2 4.0.3.
  • Joda-Time from 2.14.4 to 2.15.0 in the target platform, with the time zone database 2026e.

SCR-2053

Summary: Upgraded the Apache Kafka client to 4.3.1

Effective: 8.55.481 and later

Upgraded the Apache Kafka client from 4.0.2 to 4.3.1 in the target platform (org.apache.servicemix.bundles.kafka-clients-4.3.1-custom.jar), which the Kafka log appender uses. Brokers from version 2.1 on remain supported. No API or configuration change; no operator action is required.

SCR-2052

Summary: Upgraded Commons Lang, Tika, Guava and AWS SDK to their latest patch or minor release

Effective: 8.55.481 and later

Upgraded four third-party libraries to their latest patch or minor release. No API or configuration change; no operator action is required.

  • Apache Commons Lang from 3.20.0 to 3.21.0 in the target platform.
  • Apache Tika from 4.0.0 to 4.1.0, embedded in com.openexchange.tika.util.
  • Guava from 33.7.1 to 33.7.2 in com.google.guava.
  • AWS SDK for Java from 2.55.7 to 2.55.11, embedded in software.amazon.awssdk.

SCR-2046

Summary: Upgraded Gson Fire to 1.9.0 in the OpenCloud integration

Effective: 8.55.481 and later

Upgraded Gson Fire from 1.8.5 to 1.9.0, embedded in com.openexchange.opencloud (gson-fire-1.9.0.jar). It now requires Gson [2.10,3), which the target platform satisfies. No API or configuration change; no operator action is required.

SCR-2045

Summary: Upgraded HK2, AWS SDK and Woodstox to their latest patch or minor release

Effective: 8.55.481 and later

Upgraded HK2, the AWS SDK for Java and Woodstox to their latest patch or minor release. No API or configuration change; no operator action is required.

  • HK2 (hk2-api, hk2-locator, hk2-utils, aopalliance-repackaged) from 4.0.2 to 4.0.3 in the target platform.
  • AWS SDK for Java from 2.55.6 to 2.55.7, embedded in software.amazon.awssdk.
  • Woodstox from 7.2.2 to 7.3.0, embedded in com.ctc.wstx.

SCR-2044

Summary: Removed the unused libraries eddsa, cose-java and nekohtml and replaced PBKDF2 with the JDK implementation

Effective: 8.55.481 and later

Removed three unused third-party libraries and replaced a fourth with the JDK implementation. No configuration change; no operator action is required.

  • Removed cose-java 1.1.0 and eddsa 0.3.0 from bundle com.openexchange.multifactor.provider.webauthn, together with the cbor 4.5.6, datautilities 1.1.0 and numbers 1.8.2 jars embedded alongside them. WebAuthn verification is unaffected; it runs in com.openexchange.webauthn, which still ships cbor.
  • Removed nekohtml 1.9.22 from bundle com.openexchange.common; the packages org.cyberneko.html* are no longer exported. Custom plugins that imported them from com.openexchange.common have to ship their own copy.

  • Replaced PBKDF2 1.1.4 and its transitive dependency picketbox 4.0.21.Final in bundle com.openexchange.crypto with the JDK's PBKDF2WithHmacSHA1; keys derived for legacy encrypted data are unchanged.

SCR-2042

Summary: Upgraded transitively embedded libraries whose parent libraries still pin older releases

Effective: 8.55.481 and later

Upgraded transitively embedded libraries whose parent libraries still pin older releases. No API or configuration change; no operator action is required.

  • nimbus-jose-jwt from 10.9.1 to 10.10 in com.nimbus.
  • grpc-api and grpc-context from 1.70.0 to 1.84.0 in com.google.api.client, matching the gRPC version of the target platform.
  • jose4j from 0.9.6 to 0.9.7 in com.openexchange.file.storage.boxcom.
  • okio-jvm from 3.18.1 to 3.18.2 in com.squareup.okhttp3.
  • neethi from 3.2.3 to 3.2.4 in com.openexchange.soap.common.
  • Dropwizard metrics-core from 4.2.39 to 4.2.40 in com.openexchange.saml.
  • brownies-collections from 0.9.16 to 0.9.24 in org.magicwerk.brownies.collections; the Maven groupId moved from org.magicwerk to org.magicwerk.brownies.

SCR-2041

Summary: Upgraded the Apache Kafka client from 4.0.0 to 4.0.2 to fix CVE-2026-35554 and CVE-2026-33558

Effective: 8.55.481 and later

Upgraded the Apache Kafka client library from 4.0.0 to 4.0.2 in the target platform. It is used by the Kafka logging appender of com.openexchange.logging. No configuration change; no operator action is required.

  • Fixes CVE-2026-35554 (high: concurrent producers could corrupt or misroute records) and CVE-2026-33558 (moderate: secrets in DEBUG logs).
  • Apache ServiceMix publishes no bundle beyond 4.0.0, so the platform now ships the upstream org.apache.kafka:kafka-clients jar with the former ServiceMix OSGi manifest; the bundle symbolic name org.apache.servicemix.bundles.kafka-clients stays the same, the jar is now org.apache.servicemix.bundles.kafka-clients-4.0.2-custom.jar.

SCR-2039

Summary: Upgraded the fabric8 Kubernetes client from 7.9.0 to 8.0.0

Effective: 8.55.481 and later

Upgraded the fabric8 Kubernetes client from 7.9.0 to 8.0.0 in io.fabric8.kubernetes, which keeps using the JDK HTTP client. No configuration change; no operator action is required.

  • fabric8 8.0 moved to Jackson 3, so the bundle embeds jackson-core, jackson-databind and jackson-dataformat-yaml 3.2.3 privately; the Jackson 2 imports are gone and only com.fasterxml.jackson.annotation 2.22 is still taken from the target platform.
  • snakeyaml-engine from 3.0.1 to 3.1.1, embedded in the same bundle.

SCR-2038

Summary: Upgraded eleven third-party libraries to their latest patch or minor release

Effective: 8.55.481 and later

Upgraded eleven third-party libraries to their latest patch or minor release. No API or configuration change; no operator action is required.

  • gRPC from 1.82.2 to 1.84.0 and the Google common protos from 2.60.0 to 2.78.0 in the gRPC API jars of com.openexchange.tools.grpc.common.
  • AWS SDK for Java from 2.55.1 to 2.55.6 in software.amazon.awssdk.
  • Lettuce from 7.7.0 to 7.8.0 in io.lettuce.
  • Firebase Admin SDK from 9.10.0 to 9.11.0 in com.google.firebase.
  • Google Auth Library from 1.52.0 to 1.54.0 in com.google.api.client and com.google.firebase, and Google API Common from 2.68.0 to 2.70.0 in com.google.api.client.
  • Box Java SDK from 10.17.0 to 10.19.0 in com.openexchange.file.storage.boxcom.
  • libphonenumber from 9.0.39 to 9.0.40 in com.openexchange.sms.
  • GlassFish HA API from 3.1.13 to 3.2.0 in com.openexchange.soap.common.
  • OkHttp and its logging interceptor from 5.4.0 to 5.5.0 in com.openexchange.opencloud, matching com.squareup.okhttp3.

SCR-2037

Summary: Upgraded seven third-party libraries to their latest patch or minor release

Effective: 8.55.481 and later

Upgraded seven third-party libraries to their latest patch or minor release. No API or configuration change; no operator action is required.

  • Jackson from 2.22.2 to 2.22.3 in the target platform, including the OX repacks of the Jakarta RS providers (jackson-jakarta-rs-*-2.22.3-custom.jar) and Jackson Datatype Joda embedded in com.openexchange.imageconverter.client.

  • Logback from 1.6.3 to 1.6.5 in the target platform.

  • SLF4J and its JCL, JUL, log4j and OSGi bridges from 2.0.19 to 2.0.20 in the target platform.

  • Apache HttpCore 5 and HttpCore 5 HTTP/2 from 5.4.3 to 5.4.4 in the target platform (httpcore5-5.4.4-custom.jar, httpcore5-h2-5.4.4-custom.jar).

  • MicroProfile Health API from 4.0.1 to 4.0.2 in the target platform (microprofile-health-api-4.0.2-custom.jar).

  • Stax2 API from 4.3.0 to 4.3.1 in the target platform.

  • Protocol Buffers from 4.35.1 to 4.36.2 in the gRPC API jars of com.openexchange.tools.grpc.common, matching the version the target platform ships.

API - HTTP-API

SCR-2198

Summary: New HTTP API module accountrecovery, JSlob entries and capability account_recovery

Effective: 8.55.481 and later

  • The new module accountrecovery has the actions get, set, confirmPhone and resendVerification. They serve the user's own recovery email, phone and PIN in the Settings pane.
  • The middleware announces the capability account\_recovery while the feature is on. It can be switched off per context or user with com.openexchange.capability.account\_recovery=false.
  • Without the capability the settings pane is hidden and the forgot-password flow sends no link. An existing link answers 403.
  • A new JSlob entry io.ox/core//features/accountRecovery carries the operator flag.
  • A second new JSlob entry tells the UI which channels the deployment can deliver on.

SCR-2192

Summary: New End-Point offline_grant and Error Code MCRED-0014 for Background Mail Access

Effective: 8.55.481 and later

An OpenID Connect back-end that enables com.openexchange.oidc.offlineGrantEnabled registers <dispatcherPrefix>/oidc/<backendPath>/offline_grant, through which a client manages the user's background mail access. Every request names a live session in session and carries its secret cookie:

  • GET ?flow=authorize starts the authorization at the identity provider. The browser returns to returnTo (a path on this host) with the outcome in offlineGrant (granted, denied or failed). With display=popup, it ends instead on a page that reports the outcome to its opener and closes itself.
  • GET ?flow=status answers {"state":"none"|"granted"|"rejected","features":[...]}.
  • POST ?flow=revoke revokes the grant and answers {"revoked":true|false}.

For the users of such a back-end, scheduling a mail for later and snoozing a mail fail with MCRED-0014 (category PERMISSION_DENIED) as long as the user has not allowed background access. A client is expected to start the authorization and repeat the request. Purely additive: back-ends without the property behave as before.

See OpenID Connect 1.0 SSO for the parameters and responses.

SCR-2188

Summary: New version of shared account data in the JSlob API and error code JSNCON-0012

Effective: 8.55.481 and later

The JSlobs io.ox/core, io.ox/mail and io.ox/calendar return a version of each shared account's data in meta.sharedaccount.<id>.version, e.g. for the categories of a shared account, which all its users edit. A client that passes this version back in sharedaccount.<id>.version with jslob?action=set or jslob?action=update no longer overwrites the changes of other users: outdated but unchanged data is skipped, and outdated changed data is rejected with the new error code JSNCON-0012. Requests without a version behave as before.

SCR-2186

Summary: New folders actions home, public and sharedWithMe, and the virtual folder drive://0/

Effective: 8.55.481 and later

Clients can open the folders of a user's default file storage directly (see com.openexchange.file.storage.default) and show all storages of the user side by side:

  • folders?action=home, folders?action=public and folders?action=sharedWithMe answer the home folder, the public folders and the folders shared with the user of the default storage; where the infostore is the default, its default folder and the folders below 15 and 10.
  • The virtual folder drive://0/ in tree 1 lists the root folder of every file storage account of the user: the default storage first, then the infostore as folder 9, then the other accounts by name. It is read-only and holds no items.
  • The field isDefaultAccount of fileaccount?action=all and action=get marks the default file storage, exactly one account per user. It marked the infostore before, which is still the default unless another storage is configured.

Purely additive apart from isDefaultAccount, which only answers differently where another storage is the default. See the folders API for further details.

SCR-2158

Summary: External recipients of a share are granted access by the file storage or rejected up front

Effective: 8.55.481 and later

Sharing a folder or file with an external recipient, i.e. a person invited by their mail address, is now decided by the file storage holding the item before a guest user exists. The built-in infostore creates a guest user of the installation and notifies the recipient, as before. A storage that resolves external recipients itself, which are OpenCloud and Nextcloud, gets the recipient handed down with the address: it grants access to its own user that carries the address, Nextcloud falls back to its share by mail for an unknown address, and the storage notifies the recipient itself. Such a grant is listed as a permission of the item with type: guest, the recipient's address and display name, so that clients see and revoke it like any other permission.

  • A folder of a storage that resolves external recipients itself states external_recipients among its supported_capabilities, so that a client can offer the invitation.
  • A storage that can do neither rejects the request with the new code FILE_STORAGE-0091, an address the storage does not know with FILE_STORAGE-0092.
  • The fields com.openexchange.folder.storage.share.external of a folder and com.openexchange.file.storage.share.external of a file list the sharing links the storage holds for the item only; the shares with users and groups are the item's permissions.
  • A folder of OpenCloud states the capability permissions only where the shares of folders are expressed as their permissions (com.openexchange.file.storage.opencloud.entityResolver.folderPermissions=true), a folder of Nextcloud whenever an entity resolver is available. A request that states permissions for anyone but the user while the shares are not expressed fails with the new code FILE_STORAGE-0093 instead of being silently ignored or partially applied.

No change for the infostore and for anonymous sharing links. See the folders API and the feature documentation for further details.

SCR-2156

Summary: New field mail_identity of a fetched mail and parameter mailIdentity of inline mail image URLs in the HTTP API

Effective: 8.55.481 and later

mail?action=get returns the new string field mail_identity if the mail store knows it. The value changes when a folder is deleted and re-created under the same name, which lets the server hand out the same mail IDs again; for IMAP it is the folder's UIDVALIDITY. image/mail/picture accepts the matching optional parameter mailIdentity, so that a client can tell an inline image of the re-created folder apart from the former one.

  • mail_identity: only present if known; clients treat it as an opaque string.
  • mailIdentity: if given, it is part of the image's ETag, and a value that does not match the mail's current identity is answered like an unknown Content-ID (404). Without the parameter, the behavior is unchanged.
  • Inline image URLs that the middleware generates itself, e.g. for view=html, carry mailIdentity. These URLs change once after the update, so browsers load such images once more.

SCR-2155

Summary: New Optional Argument applyDefaultAlarms When Saving iCal Mail Attachments via the Conversion Request

Effective: 8.55.481 and later

The data handler com.openexchange.chronos.ical of the conversion request conversion?action=convert, which saves the iCal attachment of a mail as appointment, accepts the new optional argument com.openexchange.groupware.calendar.applyDefaultAlarms. When set to true, alarms contained in the iCalendar data are skipped, and the calendar user's configured default alarms are applied instead.

"datahandler": {
  "identifier": "com.openexchange.chronos.ical",
  "args": [
    {"com.openexchange.groupware.calendar.folder": "<calendar-folder-id>"},
    {"com.openexchange.groupware.calendar.applyDefaultAlarms": "true"}
  ]
}

This is the counterpart of the import parameter applyDefaultAlarms (SCR-1875) for clients that add an appointment from a mail attachment through the conversion request. The change is purely additive - without the argument, alarms are taken over as before.

See the conversion request documentation for further details.

SCR-2144

Summary: New field sendAs in the deputy permission of the HTTP API

Effective: 8.55.481 and later

The deputy permission of the deputy module in the HTTP API carries the new optional boolean field sendAs. It lets the deputy send E-Mails as the granting user, i.e. without a Sender header, as an alternative to sendOnBehalfOf. The new capability deputy_send_as tells clients whether it can be granted (see SCR-2143).

  • sendAs and sendOnBehalfOf are mutually exclusive: passing both as true fails with DEPUTY-0015. An update that sets one of them to true without passing the other one clears the other one.
  • Granting sendAs without the capability fails with DEPUTY-0016, unless the stored value already is sendAs.
  • The reverse listings action=reverse and action=reverseIds report sendAs next to sendOnBehalfOf as effective values, and return grantorAddresses for both forms. If the same granting user grants the deputy both forms through different deputy permissions, sendAs takes precedence.

When sending, only the granted form is accepted: a deputy holding sendAs who adds a Sender header is rejected with MSG-0129, also for raw messages sent with mail?action=new and for mail?action=resend (unless the granting user's address also belongs to one of the deputy's own mail accounts); a deputy holding only sendOnBehalfOf who omits the Sender header is rejected with the new code MSG-0134. Replies and forwards from the granting user's Inbox are pre-filled with the granted form, and a mail of the granting user bounced with mail?action=bounce keeps its Reply-To.

Independent of "send as" and for every user: if resolving the From and a differing Sender fails and the deputy permissions of the From user cannot be looked up either, mail?action=transport returns the original error instead of falling back to the default account's transport.

Existing payloads keep working, with two visible differences: a deputy holding only sendOnBehalfOf who omits the Sender header now gets MSG-0134 instead of the generic MSG-0056, and a client that only knows sendOnBehalfOf reads false for a grant of sendAs, while setting sendOnBehalfOf to false does not revoke sendAs. See the API documentation and the feature documentation for further details.

SCR-2123

Summary: Added push topic ox:notification:deleted for notifications removed from the notification queue

Effective: 8.55.481 and later

Notifications removed from the user's notification queue are now announced via the new push topic ox:notification:deleted with payload {"ids":[...]}: on notifications?action=delete, on notifications?action=all with delete=true, on removal by the server (e.g. a returned snoozed mail) and when the oldest notification makes room at com.openexchange.notification.queue.maxNotificationsPerUser. Live change streams subscribed to ox:notification:* receive it as event notification; via Web Push, more than about 100 identifiers are left out and the payload is flagged truncated. Expired notifications and those of deleted users or contexts are removed without an event; clients reconcile via notifications?action=all&since=0. The order of ox:notification:new and ox:notification:deleted events is not guaranteed. An unlimited queue (com.openexchange.notification.queue.maxNotificationsPerUser set to 0 or less) is no longer emptied when a notification with a key is added.

SCR-2122

Summary: Added action webpushkey and Web Push subscriptions for the App Suite UI

Effective: 8.55.481 and later

The new action pns?action=webpushkey returns the application server key (applicationServerKey) a browser needs for PushManager.subscribe(); the response carries no key if Web Push is not available. With it, client open-xchange-appsuite subscribes via pns?action=subscribe with transport webpush, topics ox:notification:* and the browser subscription in meta (pushResource, p256dh, auth, contentEncoding); other topics are rejected for this client. Web Push for the UI can be turned off via com.openexchange.pns.transport.webpush.enabled.open-xchange-appsuite=false.

SCR-2121

Summary: Added push topic ox:notification:new for notifications of the notification queue

Effective: 8.55.481 and later

A notification added to the user's notification queue (module notifications) is now announced via the new push topic ox:notification:new. Live change streams (events endpoint) subscribed to ox:notification:* receive it as the new event notification, carrying the notification as notifications?action=get returns it; Web Push and Webhooks deliver it as well. A notification skipped because one with the same key is queued already is not announced again. After a resync, clients fetch the queue via notifications?action=all&since=0. Streams need com.openexchange.pns.transport.sse.enabled, Web Push a configured VAPID key pair.

SCR-2114

Summary: Added optional field data to notifications

Effective: 8.55.481 and later

Notifications returned by the actions all and get of module notifications may carry the new optional field data: a JSON object of at most 4096 characters that lets a client act on the notification, e.g. {"module":"mail","folder":"default0/INBOX","id":"1234"} to open the mail it is about. module names the App Suite module, the other fields depend on it. The field is only present if the notification carries data; the notification about a snoozed mail that waits for a login now points to that mail. Purely additive, existing clients are unaffected.

SCR-2102

Summary: New error code OAUTHMAIL-0002 for access tokens that cannot open an external mail account's password

Effective: 8.55.481 and later

A request made with an access token that holds mail_external receives OAUTHMAIL-0002 with HTTP status 403 when the stored password of an external mail account cannot be decrypted: the token keeps no password, because it was minted under master authentication or OAuth mail access, or the user's password changed since the token was issued. Before, such a request failed with a configuration or crypto error. The primary account is not affected.

SCR-2082

Summary: Folder restriction for personal access tokens

Effective: 8.55.481 and later

accesstoken?action=new takes an optional parameter folders: a JSON object that maps a module (mail, calendar, contacts, files, tasks) to 1 to 100 folder identifiers, e.g. {"mail":["default0/INBOX"]}. On the REST collection accesstokens it goes into the POST body. accesstoken?action=all and the answer of new report it as folders. Only the MCP server /mcp accepts such a token, and it treats every other folder of a restricted module as not found. The HTTP API and all other interfaces answer it with 401 and invalid_token. A server of an earlier version ignores folders and mints an unrestricted token, so clients should offer the restriction only once all nodes are updated.

SCR-2077

Summary: New action accesstoken?action=activity

Effective: 8.55.481 and later

The access token module of the HTTP API offers accesstoken?action=activity&id=<id>&limit=<n>. It lists the calls recorded for one of the user's tokens, newest first: time, client, tool, the folder and item identifiers, preview or write, and the outcome; never content. Calls through the MCP server /mcp are recorded, under the grant of an OAuth client and under the token itself for a personal access token. id is the identifier the token listing names; limit 1 to 1000, default 1000. An identifier of no token of the user yields no entries. Requires a full session.

SCR-2075

Summary: Access token listing shows each grant of the MCP authorization server once

Effective: 8.55.481 and later

accesstoken?action=all and GET /accesstokens list what a user granted an OAuth client of the built-in authorization server of /mcp once per grant, not once per token the client gets by refreshing. Such an entry has the grant identifier as id, the client's name or redirect host as label, and expires with the grant. It carries the new object client with id, name (as the client declared it, absent if none) and redirect_host. Revoking that identifier through accesstoken?action=delete or DELETE /accesstokens/{id} revokes the grant with all its tokens. Personal access tokens are listed as before.

SCR-2067

Summary: Step-up response for restricted actions and no session identifier under external authentication

Effective: 8.55.481 and later

If external authentication is enabled, actions that require a recent authentication now answer a request whose authentication context class (ACR) is too low with HTTP status 403, the body {"error":"reauthentication_required"} and the header X-Deny-Reason: step_up_required, so a client can trigger a step-up authentication. The new error code RA-0007 ("Please re-authenticate to perform this action.") backs it.

Also the responses of login and system?action=whoami omit the field session, and the login response omits the multifactor flags. Without external authentication both responses are unchanged.

SCR-2062

Summary: Qualified Folder Identifiers in the Attachment Module

Effective: 8.55.481 and later

The folder parameter of the attachment module and the folder field of AttachmentData are now declared as string. Besides the plain numeric identifier, they accept the qualified folder identifier of a groupware account, e.g. con://37/727 for a contact in an address book shared from another context. That way, attachments of contacts in such address books can be managed like any other. Responses echo the folder identifier as requested, and attachments of foreign contacts report no creator.

Plain numeric identifiers work as before. Clients generated from the OpenAPI definition now pass the folder as a string.

See the HTTP API documentation for further details.

SCR-2043

Summary: New request sharedaccount?action=permissions and capability listPermissions for the holders of a shared account

Effective: 8.55.481 and later

Users of a shared account can be allowed to see who else has access to it.

GET /ajax/sharedaccount?action=permissions&accountId=[user]@[context] answers with one entry per user or group holding a permission, including the holders in other contexts. An entity of a foreign context is identified by its qualified [user]@[context] form alone and carries no numeric entity, the same way it appears in a folder permission. The listing reports who holds a permission, not which permission each of them holds, and is preliminary.

Access is decided by the new shared account capability listPermissions, evaluated like every other capability of a shared account. It is not granted by default: add it to com.openexchange.sharedaccount.defaultCapabilities so that everyone using a shared account sees the list, or grant it per permission so that only selected users do. Denying it for a single permission takes it away from that holder only. Without it the request is answered with SAC-0009.

Purely additive, and without configuration nobody can call it.

See the feature documentation, as well as the HTTP API documentation for further details.

SCR-2028

Summary: Changed status and scope handling of OAuth account requests

Effective: 8.55.481 and later

The status of an OAuth account association is now invalid_grant if the access token of the account is no longer valid, and ok if the OAuth provider or the database cannot be reached for the moment; recreation_needed remains for an account that cannot be used at all. oauth/accounts?action=init leaves out requested scopes that are disabled for the user through com.openexchange.oauth.modules.enabled.<provider> and refuses the request with OAUTH-0043 only if none remains. oauth/accounts?action=create requires the session secret like any other request; the token of the call-back URL no longer replaces it. oauth/proxy refuses provider responses larger than 4 MiB. The App Suite UI needs no adjustment.

SCR-2020

Summary: New Mobile API endpoints for message lists, conversations and search

Effective: 8.55.481 and later

The Mobile API gains GET /mobile/v1/mail/folders/{folderId}/messages, GET /mobile/v1/mail/folders/{folderId}/threads and POST /mobile/v1/mail/search. Native mail apps use them to list and search the messages and conversations of a folder, newest first and in pages. The cursor stays correct while mail arrives or is removed. Lists filter by unseen, flagged, categoryId and a receivedAfter window, and return the state for message-changes. A search field, operator or scope the mail server cannot search is answered with 400, never with all messages. hasAttachments follows the keywords $HasAttachment and $HasNoAttachment (Dovecot mail_attachment_detection_options = add-flags), else a multipart/mixed Content-Type, the same in lists and in search. Conversations need threading on the mail server (501 threading_unsupported otherwise). The endpoints need the scope read_mail.

POST /mobile/v1/mail/search also searches all mail accounts of the user with scope.allAccounts = true: the subscribed folders that hold messages, trash and spam left out, merged newest first. An account that cannot be searched is named in unavailableAccounts of the page instead of failing the search. Such a search counts once per account against com.openexchange.mobile.api.rateLimit.requests.

A search across accounts counts all its accounts against the budget at once: if not enough are left, it fails with 429 without counting any, and Retry-After covers all of them. The primary account, too, is named in unavailableAccounts if it cannot be searched in time.

POST /mobile/v1/mail/search searches one mail account with scope.accountId: its subscribed folders that hold messages, trash and spam left out, as with scope.allAccounts. Such a search counts once against the request budget. An account the user does not have is answered with 400; an account that cannot be searched in time is named in unavailableAccounts of an empty page.

With scope.allAccounts and scope.accountId, a folder that cannot be searched, e.g. because access to it was withdrawn, is left out of the page and named in unavailableFolders; the other folders are searched as usual.

SCR-2018

Summary: New Mobile API endpoints to read a message, its body, source, attachments and attachment previews

Effective: 8.55.481 and later

The Mobile API gains five operations for reading one message, all with scope read_mail and none of them marking the message seen: GET /mobile/v1/mail/messages/{messageId} returns headers, flags and the attachment list; .../body returns the body sanitized against the server's allow-list, as HTML or text, with externalContent (block, proxy, allow) and maxBytes, and proxied images get absolute URLs; .../raw and .../attachments/{attachmentId} return the source and an attachment with Range support (206 with the part's content type, 416); .../attachments/{attachmentId}/preview returns a scaled image of a picture or, with the document converter, of a document's first page, 202 while it renders and 404 with code preview_unavailable without a converter or for a later page.

Where virus scanning is enforced, source, attachments and previews are scanned first; infected content is refused with 403 and code content_blocked. A message that offers one-click unsubscription (RFC 8058) carries listUnsubscribeOneClick, and readReceiptRequested is always false in the sent and drafts folders.

Sending the read receipt a message asks for: POST /mobile/v1/mail/messages/{messageId}/read-receipt (scope write_mail, honors Push-Subscription-Id) sends it and sets $MDNSent, so readReceiptRequested turns false on every device and no other device offers the receipt again. The receipt goes out from the user's address the message was sent to, an alias included, else from the send address; for an external account from that account's address. A receipt sent before is not sent again and answered with 204. A message that asks for no receipt, and every message in the sent and drafts folders, is answered with 409 and the new code read_receipt_not_requested.

The read receipt accepts an optional Idempotency-Key and is marked sent before it goes out, so it is sent at most once even if several devices send it at the same time.

SCR-2017

Summary: New Mobile API endpoint to change many messages at once

Effective: 8.55.481 and later

The Mobile API gains POST /mobile/v1/mail/message-bulk, with which native mail apps change any number of messages in one call: set seen, flagged, answered, color, categoryId and keywords, and move, copy, archive, spam, notSpam, trash or deletePermanently. Up to 50 operations run in order, each with its own result: 200, 207 with the failed identifiers and their problem, or an error status; a failing operation does not stop the others. Where message identifiers do not survive moves, the new ones are listed in moved; copies are listed in copies. The call needs the scope write_mail and requires Idempotency-Key; a retry after a lost response gets the kept result, which is kept up to 1 MB even if com.openexchange.ajax.idempotency.maxResultSize is lower. All operations together may name at most 1000 identifiers (Me.limits.maxBulkIds); more are answered with 413.

The response also carries states: for each folder the operations changed, the state right before and after them, as oldState and newState for GET /mobile/v1/mail/folders/{folderId}/message-changes. A folder is listed only if every change in between was one of the request's own; after a change by another client, or without CONDSTORE, it is left out and the app syncs as usual.

SCR-2014

Summary: New Mobile API operations for live events and batch requests

Effective: 8.55.481 and later

The Mobile API gets two operations:

  • GET /mobile/v1/events: live changes as Server-Sent Events. state events carry an EventPayload with the API's folder identifiers and the topics mail.message.* and mail.folder.changed. The stream needs scope read_mail, skips changes made by its own device and answers 404 where com.openexchange.pns.transport.sse.enabled is false for the user.

  • POST /mobile/v1/batch: up to 20 operations in one request, run in order. An entry can refer to results of earlier entries with $ref:<id>#<JSON pointer>. Each entry carries its own status; scopes and Idempotency-Key apply per entry.

At <dispatcher prefix>events, HEAD now answers 405 instead of opening a stream, and errors use the problem format of the Mobile API: each carries a code, e.g. invalid_token, and a type of https://documentation.open-xchange.com/mobile/v1/problems/<code>. Status codes and headers are unchanged.

A batch entry with forEach runs once per element of an array an earlier entry returned, e.g. once per folder; $item stands for the element. Its body lists the result of each run. All runs of one batch are bounded by com.openexchange.mobile.api.batch.maxFanOut (Me.limits.maxBatchFanOut); an entry beyond fails with 413. Each run counts against com.openexchange.mobile.api.rateLimit.requests.

In mode idp, a Push-Subscription-Id that names none of the user's subscriptions is ignored when a stream opens, so it cannot get around the limit of streams per user. A forEach over an operation that requires an Idempotency-Key, e.g. sending, fails with 400 and does not run.

SCR-2013

Summary: New Mobile API endpoint for the message changes of a mail folder

Effective: 8.55.481 and later

The Mobile API gains GET /mobile/v1/mail/folders/{folderId}/message-changes, with which native mail apps fetch the messages created, updated and destroyed in a folder since a state taken from the folder list or from an earlier call. A call returns at most limit created and updated messages (default and maximum 500) and hasMore; include embeds fields of those messages, never their body. On IMAP the server needs CONDSTORE and QRESYNC; JMAP accounts are supported as well. A state that is too old, belongs to another folder or cannot be computed is answered with 410 and code cannot_calculate_changes. The endpoint needs the scope read_mail.

SCR-2012

Summary: New Mobile API endpoints for mail folders

Effective: 8.55.481 and later

The Mobile API gains /mobile/v1/mail/folders, with which native mail apps read and manage the mail folders of all accounts. GET /mobile/v1/mail/folders returns a flat list with parentId, counts and, per folder, a state for message changes; on IMAP servers with LIST-STATUS and CONDSTORE the states of all folders of an account come from one command, and If-None-Match answers 304 while nothing changed. POST creates a folder and requires Idempotency-Key; GET, PATCH (application/merge-patch+json: rename, move, subscribe) and DELETE (to the trash unless permanent=true) work on /mobile/v1/mail/folders/{folderId}. Writes need If-Match (428 without it, 412 when stale); a name clash is answered with 409 and code folder_exists. Reads need the scope read_mail, writes write_mail. On Dovecot and JMAP a folder keeps its identifier when it is renamed or moved.

SCR-2010

Summary: New Mobile API endpoints for sign-in, account data and recipient suggestions

Effective: 8.55.481 and later

The Mobile API gains the endpoints a native mail app needs to sign in and load the account. In mode token, POST /mobile/v1/auth/token exchanges login, password and device name for a personal access token. A user with a second factor gets 401 with second_factor_required and a challenge, answered through POST /mobile/v1/auth/token/second-factor with a TOTP, backup or SMS code; a first call without code sends the SMS and returns 202. GET /mobile/v1/auth/token reads the presented token, DELETE /mobile/v1/auth/token revokes it. In mode idp all four answer 404. In both modes, GET /mobile/v1/me returns user, scopes and settings with an ETag; GET /mobile/v1/mail/accounts lists mail accounts with stableMessageIds, stableFolderIds and a state: ok, credentials_invalid, unreachable or secret_unavailable (the stored password cannot be decrypted for the request, e.g. an external account whose password is encrypted with the login password, which the access token does not provide; folder and message requests for such an account get 403 with mail_access_unavailable); GET /mobile/v1/mail/signatures, GET /mobile/v1/mail/categories (with unread counts) and GET /mobile/v1/contacts/autocomplete return signatures, categories and recipient suggestions. Sign-in shares lockout and rate limits with the access token sign-in.

The login name of POST /mobile/v1/auth/token is limited to 256 characters.

In mode token, POST /mobile/v1/auth/token/rotate issues a new secret for the presented token and renews its lifetime: the new expiresAt is now plus the lifetime the token was minted with, capped by com.openexchange.accesstoken.maxLifetimeDays. Identifier, scopes, push subscriptions, the kept mail credential and scheduled mails stay. The presented secret stays valid for graceSeconds (300) or until the next rotation; a retry with the same secret and Idempotency-Key gets the same new secret. Of two rotations with the same secret, the second gets 409 with code conflict; a rotation with a secret that another rotation replaced more than a minute earlier revokes the token. The response of GET /mobile/v1/auth/token and of a sign-in now carries rotateAfter, a quarter of the lifetime. In mode idp the operation answers 404, and it cannot be part of a batch.

SCR-2007

Summary: New Mobile API endpoints for push subscriptions

Effective: 8.55.481 and later

The Mobile API gains /mobile/v1/push/subscriptions, with which native mail apps register a device for push notifications through APNs or FCM. POST registers the device, optionally with Idempotency-Key; GET lists the subscriptions of the token or OAuth client or reads one by subscriptionId; PATCH (application/merge-patch+json) changes one; DELETE removes it. All need the scope read_mail. Registering the same device token again replaces the subscription and keeps its identifier. Invalid input is answered with 400 or 422 and the field in errors[].pointer, a body over 64 KiB with 413. A subscription made with an access token ends with the token; one made in mode idp ends after 30 days without renewal.

Revoking an access token releases the push credential only if it was copied from that token; one kept from a password session or another token stays. A PATCH of the topics or the environment sets up the mail listener for new-message pushes like a registration does.

SCR-1995

Summary: New Mobile API for native mail apps at /mobile/v1

Effective: 8.55.481 and later

The middleware serves a resource-oriented HTTP API for native mail apps at /mobile/v1, described by its own OpenAPI document. This release brings the foundation every operation builds on; the mail operations follow.

  • Every request carries a bearer token. A deployment signs in either with personal access tokens (oxa_…) or with the operator's identity provider, never with both; a token of the other kind is answered with 401.
  • GET /mobile/v1/auth/config needs no token and tells a client which of the two modes applies and what it needs for it.
  • Errors are application/problem+json (RFC 9457) with a stable code clients switch on, the middleware's own error code as oxCode and the request's tracking identifier as instance.
  • Every GET also answers HEAD. An unknown path is 404, a known path with another method 405 with Allow.
  • If-None-Match answers 304. The write operations that follow will answer 428 without If-Match and 412 with the current representation when it is stale.

The API answers only where com.openexchange.mobile.api.enabled is set, and it needs the OAuth provider to validate tokens. Existing endpoints are unaffected.

The server bounds how many requests a user makes per time window and how many run at once; each entry of a batch counts, the event stream does not. Beyond that, a request is answered with 429, code rate_limited and Retry-After without any effect; the client waits that long and retries. The limits are set through com.openexchange.mobile.api.rateLimit.*, com.openexchange.mobile.api.idempotency.* and com.openexchange.mobile.api.uploads.maxConcurrent. In mode idp, a token the identity provider issued to another client is answered with 401 and invalid_token unless com.openexchange.mobile.auth.idp.checkAudience is false.

The Mobile API gains GET /mobile/v1/mail/folder-changes, with which native mail apps fetch the folders created, updated and destroyed since the state of an earlier folder list, instead of reloading the whole list. GET /mobile/v1/mail/folders now returns that state at the top level. The delta embeds the created and updated folders in folders and maps former to new identifiers in renamed for accounts whose folder identifiers change on a rename. A call returns at most limit identifiers (default and maximum 500) and sets hasMore when more follow. The state covers the accounts, subscribedOnly and, if the list asked for them, the counts of the list it came from. A state that is unknown, expired or whose account is gone is answered with 410 and code cannot_calculate_changes; the client reloads the list. The middleware keeps a snapshot per state in Redis, at most 50 and 1.5 MiB per user for 7 days after the last use; a list of more than about 5000 folders gets no state. IMAP and JMAP accounts are supported.

A failing key-value store is answered with 503 and Retry-After instead of 500. While the store cannot be reached, an operation that requires an Idempotency-Key, such as sending, performs nothing and is answered the same way; one with an optional key runs without the protection. GET /mobile/v1/mail/folders returns no state while an account could not be read; an account without mail access, e.g. in state secret_unavailable, counts as read without folders. At the snapshot limit, superseded states are dropped first. For JMAP accounts, a delta with counts reports every change for all folders of the account.

Clients send Accept: application/problem+json together with application/json on every request; the problem body is guaranteed only when Accept allows it. A 401 may carry more than one WWW-Authenticate challenge; clients evaluate the Bearer challenge and ignore the others. The middleware itself keeps sending the problem body whatever Accept says, with a single challenge, so a client that follows both rules behaves the same whether or not an authentication layer checks tokens in front of the middleware.

POST /mobile/v1/mail/folders/{folderId}/empty removes all messages of a folder in one call: they go to the trash unless the folder is in the trash, permanent=true is given or the user deletes for good. It requires Idempotency-Key. POST /mobile/v1/mail/folders/{folderId}/mark-read marks all messages of a folder as read. GET /mobile/v1/mail/accounts/{accountId}/quota tells how much of its storage and message quota a mail account uses; a quota the mailbox does not have is left out.

With categoryId, mark-read marks only the messages of that inbox category, the same ones listMessages with categoryId lists; it is accepted for the inbox of the primary account only.

SCR-1988

Summary: Calendar Folders of a Shared Account Report Their Own Folder Type

Effective: 8.55.481 and later

The calendar folders of a shared account report the folder type they have within the account. Previously they were reported as "shared" to the requesting user, whatever their type in the account was.

  • type is 1 ("private") for the account's calendars, where it was 3 ("shared") before.
  • The folders are listed in the private section of folders?action=allVisible instead of the shared one.
  • A Trash folder of the account is reported with its own type 16.
  • Appointments of the account are found by the contact halo, which searches the calendar user's private and public folders.

A client that reads type == 1 as "belongs to the acting user" will now include a shared account's calendars in that answer. The property to test instead is com.openexchange.calendar.provider, which is sharedaccount for exactly these folders.

The contents of the folders are unaffected. Classification, default participation status and permissions are decided within the shared account's own session, where the calendar user is the account itself: an appointment classified as PRIVATE in such a calendar is delivered to every user of the account in full, as before.

See the HTTP API documentation for further details.

SCR-1974

Summary: New capabilities access_tokens and mcp

Effective: 8.55.481 and later

Two new capabilities tell a client what to offer before it calls anything.

access_tokens is awarded to a user who may mint personal access tokens: the user is neither a guest nor anonymous, and the OAuth provider is enabled for the user. These are the checks the accesstoken module applies before minting, so a settings page shown only with this capability never offers what the module would refuse.

mcp is awarded to a user who can use the MCP endpoint: the endpoint is registered on the node, the user is neither a guest nor anonymous, and the OAuth provider is enabled for the user. It is independent of access_tokens, since personal access tokens serve more than the MCP endpoint and an MCP client may also bring a token from an external authorization server. The endpoint checks the capability itself on every request, including an override through com.openexchange.capability.forced.mcp, and refuses a disabled context there as well. Switching the OAuth provider or the capability off for a user or context therefore refuses that user's tokens with 403 at once, including tokens issued before.

No admin action. access_tokens follows com.openexchange.oauth.provider.enabled; mcp also follows com.openexchange.mcp.enabled and whether the open-xchange-mcp package is installed.

SCR-1946

Summary: New HTTP API module accesstoken for personal access tokens

Effective: 8.55.481 and later

The new module accesstoken lets a user mint bearer tokens for clients that cannot run an OAuth flow, such as a script or an MCP client with a fixed Authorization header: new (parameters label, scopes, expires) returns the token metadata and, once, the secret oxa_<context-id>_<random>; all lists the user's tokens together with the scopes the user may grant (grantable_scopes, each as scope and description); delete revokes one. The actions require a full session of a regular user: a session made from a token cannot mint tokens, and guest users cannot mint tokens at all (ACCESSTOKEN-0004). The module is registered only while the OAuth provider is enabled, and minting is refused where the provider is disabled for the user (ACCESSTOKEN-0005). The bundles com.openexchange.accesstoken (API), com.openexchange.accesstoken.impl (storage, validator plug-in, clean-up, password-change handler, mail guard) and com.openexchange.accesstoken.json (the module) ship in the package open-xchange-core, since the tokens are a bearer credential for every OAuth-protected endpoint.

The same actions are also available REST-like on the collection accesstokens below the dispatcher prefix, in the style of the mail compose REST API: GET accesstokens lists the tokens, POST accesstokens mints one from a JSON body with the fields label, scopes (an array or a comma-separated string) and expires, and DELETE accesstokens/{id} revokes one. As with the module, errors are answered with 200 and the error in the JSON body.

A token is bound to its user and limited to the scopes chosen at minting. The grantable scopes are the ones the installed modules register with the OAuth provider (OAuthScopeProvider, e.g. read_contacts, write_contacts, read_mail, read_calendar), offered only where the user's capabilities admit the module. Two limits apply, both configurable (com.openexchange.accesstoken.maxLifetimeDays, default 365, and com.openexchange.accesstoken.maxTokensPerUser, default 50). The token is accepted as bearer token by every endpoint that validates tokens through the OAuth provider; the HTTP API modules with restricted actions take it in place of the session parameter. A request outside the token's scopes is 403 with insufficient_scope; an unknown or revoked token is 401 with invalid_token, an expired one 401 with a description naming the expiry; when the token cannot be checked because the database is unavailable, the answer is 503 with temporarily_unavailable and the client keeps its token.

For mail access the token stores no credential of its own: minting asks the mail credential vault (feature access-token) to keep what the session provides, sealed with the token's secret, and the listing reports whether it did as mail_access. Under master authentication (com.openexchange.mail.passwordSource=global) the vault records that nothing is needed, so mail_access is true; a session without password or OAuth tokens mints a token with mail_access false, and such a token never reaches the mail server. A password change the user makes through App Suite revokes every token of the user; a password set through provisioning does not, since that path posts no password-change event. A token minted without mail credential is refused at the mail server with ACCESSTOKEN-0008 instead of presenting its secret there. Expired tokens are dropped by a clean-up job a week after their expiry.

SCR-1873

Summary: New Restore Action and Soft-Delete Parameters in the Chronos Module

Effective: 8.55.481 and later

The calendar Trash folder adds one action and several parameters to the HTTP API. The action and the parameters are additive, but the behavior of an ordinary delete changes with them: the feature is disabled by default (com.openexchange.calendar.trashFolder.enabled); where it is switched on for a user, PUT /chronos?action=delete moves an appointment into the Trash instead of removing it, and a caller that wants the permanent delete passes harddelete=true. The OpenAPI definitions live in http-api/http_api/.

  • PUT /chronos?action=restore - puts a soft-deleted event back, answering with ChronosRestoreResultResponse (RestoreData, RestoreDetails).
  • PUT /chronos?action=delete - new harddelete, bypassing the Trash, and new undo, answering with an undo_token for the undo module.
  • PUT /chronos?action=update and PUT /chronos?action=updateAttendee - new harddelete, for the occurrences an update takes out of a series.
  • PUT /folders?action=delete - the existing hardDelete now also decides the fate of what the deleted folder holds.
  • New dryRun, outcome and targetFolder parameters, the new trashed event flag, the new trash folder capability and the calendar_trash capability.
  • New read-only event fields trashedFrom, trashedBy and trashedAt, present while an event sits in the calendar user's Trash folder - where it came from, who deleted it and when, the last being what a retention window is counted against. Reported on the event whichever row stores them, so a client reads them in one place.
  • warnings is now declared on the calendar result responses (ChronosCalendarResultResponse, ChronosMultipleCalendarResultResponse, ChronosRestoreResultResponse), where the envelope has always been able to carry it.
  • New meta object on the calendar result of PUT /chronos?action=delete and PUT /chronos?action=update, currently holding trashFolderId: the Trash folder provisioned while carrying out that very request, as a composite folder identifier. The folder is created on the calendar user's first soft deletion, so it appears in the folder tree as a side effect of a request about appointments; naming it lets a client add it to a tree it already holds. Present only on the request that created the folder, and carried in the payload rather than as a warning, a warning on the envelope being lost when a client bundles its requests into a multiple.
  • Ten new error codes: CAL-4123 to CAL-4129 and CAL-41210 to CAL-41212.

A restore is evaluated before it is applied, the calendar having moved on while the event sat in the Trash: the action answers with the ways it can come back, dryRun returns that evaluation without writing anything, and outcome commits to one of them. Where a trashed date's series is in the Trash as well, the evaluation names that series' own Trash entry in verdicts.sourceEntry (folder, id), which the CAL-4124 refusal carries too: a binned series is stored under a fresh unique identifier, so nothing on the date's own entry leads to it. An undo_token is only handed out where the deletion can be reversed whole - several occurrences of one series deleted at once share a Trash entry and yield none. A result reports what became of the entry in the folder views the request covers, so a client that wants the Trash entry named - on a delete, or on a restore that empties it - passes expand=true.

Each way back carries a translated label and, where the label alone does not say what it does, a one-sentence consequence; situation carries one sentence per thing standing in the way, followed by one consequence for other people where the restore has it: an organizer's restore invites the participants again. Dates are left out of the sentences; verdicts.occurrences names them where an entry holds several. The outcome rejoinAsAddedDate is reserved and never offered. restoreRebased is offered only where following the series actually changes the date; otherwise the plain restore is the only way back. With checkConflicts=true, a taken slot is reported as conflicts with status refused, as on create and update, rather than as an error.

An incoming cancellation is not applied unattended where it would leave dates the user has soft-deleted with nothing to go back into: a series called off while individual dates of it sit in the user's Trash folder answers with CAL-41212 instead, so the decision is theirs. Applying it explicitly is unaffected; the interactive analysis of such a message names the dates concerned.

Two effects reach beyond the calendar: hardDelete=true on /folders?action=delete now removes a deleted folder's contacts permanently instead of moving them to the contacts Trash, and the undo module now reports a failure where an undone operation answers with an error, instead of reporting success having restored nothing.

See the Chronos API and the Folders API, as well as the "Trash Folder / Soft Delete" section of the calendar implementation details for further details.

API - Java

SCR-2175

Summary: DBPool Moved to the Package com.openexchange.server.database

Effective: 8.55.481 and later

The class DBPool moved from the package com.openexchange.server.impl to com.openexchange.server.database; code using it has to import it from there, and a bundle needs com.openexchange.server.database in its Import-Package. The server-internal classes Starter, InMemoryReplicas and Constants of that package moved to the unexported package com.openexchange.server.internal. The classes are otherwise unchanged. The packages com.openexchange.server.impl, com.openexchange.groupware.container, com.openexchange.groupware.contact.helpers, com.openexchange.groupware.search and com.openexchange.ajax.fields are now exported by the new bundle com.openexchange.groupware.container instead of com.openexchange.server, under the same names, so existing imports keep resolving.

SCR-2068

Summary: Replaced the scope flags of the RestrictedAction annotation by an ACR check

Effective: 8.55.481 and later

The annotation com.openexchange.ajax.requesthandler.annotation.restricted.RestrictedAction replaces the attributes enforceCustomRestrictedAccessCheckForBasicScope and requiresFullAuth by requiresACRCheck (default false) and getMinACRValue (new enum com.openexchange.session.ACRValue, default FRESH). GeneralScopes.BASIC and GeneralScopes.ELEVATED are merged into GeneralScopes.ALL (*), and Scope.hasBasicAccess() is removed.

Custom actions using the removed attributes or constants have to be adapted.

API - REST

SCR-2197

Summary: New REST API /account-recovery for password reset and administrative recovery details

Effective: 8.55.481 and later

Public endpoints without authentication:* POST /account\-recovery/v1/forgot\-password starts a recovery. The response is the same whether the address matched or not.

  • GET /account\-recovery/v1/reset?token=… validates a token and returns the primary address in masked form.
  • POST /account\-recovery/v1/reset consumes the token and changes the password.
  • GET /account\-recovery/v1/password\-requirements returns the password policy. An optional token parameter selects that user's policy.
  • GET|POST /account\-recovery/v1/verify\-email confirms a recovery email address.
  • The legacy paths /account\-recovery/request, /account\-recovery/waypoint, /account\-recovery/reset and /account\-recovery/requirements behave the same for existing integrations.

Status codes:

  • 410 for an unknown, expired or used token.
  • 403 for a user without the account\_recovery capability.
  • 503 when no password change backend is available.

Administrative endpoints with HTTP basic authentication as master or context administrator. They take values in the JSON body only:

  • GET|PUT /admin/v1/account\-recovery/details/email/{email}
  • PUT /admin/v1/account\-recovery/password/email/{email}

SCR-2147

Summary: New attribute sendAs in the SCIM resource Deputies

Effective: 8.55.481 and later

The SCIM resource Deputies (schema urn:ietf:params:scim:schemas:extension:openxchange:2.0:Deputy) carries the new boolean attribute sendAs. It lets the deputy send E-Mails as the grantor without a Sender header and is mutually exclusive with sendOnBehalfOf; a request setting both to true is rejected, and setting sendOnBehalfOf to false does not revoke sendAs, so both have to be false to revoke any sending right. As with sendOnBehalfOf, a deputy permission granted to a group applies to every member; if the same deputy holds both forms from one grantor, e.g. directly and through a group, sendAs takes precedence. Like the other administrative interfaces, SCIM is not restricted by com.openexchange.deputy.sendAsEnabled, but while it is disabled for the grantor, sendAs acts as sendOnBehalfOf (see SCR-2143).

Existing SCIM clients keep working. Since every deputy resource now carries sendAs, its meta.version (ETag) changes once with this update: a conditional request with an ETag read before the update fails once with 412 Precondition Failed, and the client has to read the resource again. See the SCIM documentation for further details.

SCR-2141

Summary: New MailCredentialAdminService operation to search a context's kept mail credentials

Effective: 8.55.481 and later

The com.openexchange.grpc.provisioning.MailCredentialAdminService has the new operation SearchMailCredentials (HTTP gateway: GET /prov/v1/contexts/{context_id}/mail-credentials). It returns the credentials kept in a context with the user each is kept for, optionally filtered by state and feature, page_size at a time (default 100, at most 1000); next_page_token leads to the next page. MailCredential now carries user_id in every answer, so ?state=rejected names the users behind appsuite_mailcredential_rows_rejected. To use it over HTTP, add the service to the gateway's services.

SCR-2106

Summary: New MailCredentialAdminService operations to repair or refresh a kept mail credential

Effective: 8.55.481 and later

com.openexchange.grpc.provisioning.MailCredentialAdminService has two new operations. Each acts on one kept mail credential right away instead of waiting for the maintenance job, and answers with an outcome and the credential as it stands afterwards.

  • RepairMailCredential (HTTP gateway: POST /prov/v1/contexts/{context_id}/users/{user_id}/mail-credentials/{credential_id}:repair) repairs a credential whose refresh token the identity provider rejected, from a live session of the user. Outcomes: repaired, no_live_session, failed, not_rejected, caller_key, not_found.
  • RefreshMailCredential (HTTP gateway: POST …/mail-credentials/{credential_id}:refresh) refreshes its tokens at the identity provider regardless of schedule. Outcomes: refreshed, not_refreshable, rejected, deferred, failed, caller_key, not_found.

To use them over HTTP, add the service to the gateway's services.

SCR-2098

Summary: New provisioning service MailCredentialAdminService for a user's kept mail credentials

Effective: 8.55.481 and later

The provisioning API gets the service MailCredentialAdminService (mailcredential.proto). A context or master administrator lists and releases the mail credentials the vault keeps for a user. Over the provisioning HTTP gateway it answers under /prov/v1/contexts/{context_id}/users/{user_id}/mail-credentials:

  • GET .../mail-credentials: the user's kept credentials, oldest first, with id, feature, kind (session, exchanged, master), callerKey, created, expires, state (kept_alive, due, not_kept_alive, rejected, expired) and refreshDue. Nothing returned reveals what a credential holds or the login it was kept for.
  • DELETE .../mail-credentials/{credential_id}: releases one; a credential of another user is not released (released: false).
  • DELETE .../mail-credentials?feature=<feature>: releases all of a feature, e.g. push.

A release logs out exchanged tokens. Over RMI the same is OXMailCredentialInterface (OXMailCredential). The gateway does not expose the service by default; add it to the gateway's services. Purely additive.

SCR-2065

Summary: New and changed REST end-points under /authentication/v1 for the external authentication service

Effective: 8.55.481 and later

The REST end-points of bundle com.openexchange.external.authentication, protected by Basic authentication, gain the resources the external authentication service drives:

  • POST /authentication/v1/oidc/authorize-url, /handoff, /refresh, /logout, /end-sessions and /logout-token/verify - the OpenID Connect flow, from building the authorization URL to verifying a back-channel logout token
  • POST /authentication/v1/multifactor?action=list|startAuthentication|finishAuthentication - the multifactor devices of a user and their authentication
  • POST /authentication/v1/login-handlers - triggers the middleware's login handlers out of band, since no login runs through the middleware
  • POST /authentication/v1/login?loginAction= with the new actions guest, shareResolve and resetGuestPassword; the action share is replaced by shareResolve

A login answered with a challenge (e.g. a password-protected share or a second factor) now returns it in the response body instead of a plain failure.

All errors of these end-points are answered with the standard error JSON. A rejected request is answered with 400 or 403 and is not worth retrying, e.g. invalid credentials, an unknown or expired OIDC flow token, an invalid logout token or a refresh token the provider rejected for good (new error code OIDC-0029); a server fault is answered with 5xx.

See the REST API documentation for further details.

SCR-2025

Summary: New provisioning service MailFilterAdminService for a user's mail filter rules

Effective: 8.55.481 and later

The provisioning API gets the service MailFilterAdminService (mailfilter.proto). A context or master administrator reads and changes the mail filter rules of a user without the user's password. Over the provisioning HTTP gateway it answers under /prov/v1/contexts/{context_id}/users/{user_id}/mailfilter:

  • GET .../mailfilter: whether administrative access applies, the strategy in use, the Sieve capabilities and the script_hash of the active script
  • GET and POST .../mailfilter/rules, GET, PATCH and DELETE .../mailfilter/rules/{rule_id}, POST .../mailfilter/rules:reorder and POST .../mailfilter:purge
  • GET .../mailfilter/script: the active script and its hash

A rule is the mail filter JSON of HTTP API v2 in the field definition. Every write takes an optional if_match; if the active script changed since that hash was read, the call yields 409 and writes nothing; the check is best effort, so a write by another node or ManageSieve client in between can still be overwritten. Access goes through a token, DoveAdm or master authentication, see SCR-2023. A caller can pass a token the mail server accepts in the header mail-authorization: Bearer <token>; it applies only to the user the call addresses by identifier, and a token the mail server rejects yields 403. DeputyPermissionService accepts the same header. The gateway does not expose the service by default, see SCR-2024. Purely additive.

A token login on a ManageSieve server that lacks a matching SASL mechanism fails with MAIL_FILTER-0051 and gRPC status FAILED_PRECONDITION instead of falling back to PLAIN; an unknown user_id yields NOT_FOUND.

API - RMI

SCR-2209

Summary: RMI status and listing methods require administrator credentials

Effective: 8.55.481 and later

The methods getMigrationStatus and getLockStatus of the RMI interface DBMigrationRMIService take an additional Credentials parameter and require the master administrator, as forceMigration, rollbackMigration and releaseLocks already do. Before, they checked no credentials. The command-line tool dbmigrations already asks for these credentials and now passes them on. Clients calling the RMI interface directly must pass credentials. Both methods can now also be forwarded to the site that holds the schema, which SCR-1882 left open.

The read methods of four more RMI interfaces take an additional Credentials parameter, too. Before, they checked no credentials:

  • ConsistencyRMIService: all listMissingFiles* and listUnassignedFiles* methods require the master administrator.

  • FileChecksumsRMIService: listFilesWithoutChecksumInContext requires the context administrator, listFilesWithoutChecksumInDatabase and listAllFilesWithoutChecksum the master administrator.

  • LoginCounterRMIService: getLastLoginTimeStamp requires the context administrator.

  • ShareRMIService: listShares by context, or by context and guest, requires the context administrator; by token, the master administrator.

Over RMI, UpdateTaskRMIService now rejects getExecutedTasksList, getPendingTasksList and runUpdateFor without credentials; use the variants that take credentials.

The tools checkconsistency, calculatefilechecksums, shares and lastlogintimestamp already ask for administrator credentials and now pass them on. lastlogintimestamp used to ignore them and now requires the context administrator.

SCR-2199

Summary: Recovery details in the RMI and SOAP provisioning API

Effective: 8.55.481 and later

  • com.openexchange.admin.rmi.dataobjects.User gains recoveryEmail, recoveryPhone and recoveryPin, each with get, set and is…Set methods.
  • createuser and changeuser through RMI write these fields to user\_recovery\_details. An empty string clears a field, and an unset field leaves it unchanged.
  • The SOAP User data object of the user, context and reseller services carries the same three fields.
  • A provisioned password change revokes the user's open reset links.

SCR-2184

Summary: ExternalAccountRMIService list methods require administrator credentials; listexternalaccounts and deleteexternalaccounts accept the context administrator

Effective: 8.55.481 and later

All list methods of the RMI interface ExternalAccountRMIService take an additional Credentials parameter and authenticate it against the given context, as delete already does. Before, they checked no credentials at all. The context administrator is accepted; the master administrator only if MASTER_ACCOUNT_OVERRIDE is enabled. Accordingly, listexternalaccounts and deleteexternalaccounts now take the context administrator's credentials. Scripts that call listexternalaccounts as master administrator need MASTER_ACCOUNT_OVERRIDE=true or have to switch to the context administrator. Clients calling the RMI interface directly must pass credentials.

SCR-2177

Summary: DataExportRMIService requires credentials for read operations and offers administrative data exports

Effective: 8.55.481 and later

The read operations of DataExportRMIService take an additional Credentials parameter and reject callers without valid administrator credentials:

  • getDataExportTask and getDataExportTasks(int, Credentials) require the context administrator, the master administrator only where MASTER_ACCOUNT_OVERRIDE is enabled
  • getDataExportTasks(Credentials), getOrphanedWorkItems, getOrphanedFileStoreLocations and getOrphanedResultFiles require the master administrator

The command-line tools listdataexports and dataexportconsistency already ask for these credentials and now pass them on. RMI clients calling the old signatures have to be updated. The read operations of a context can now also be forwarded to the site that holds it, which SCR-1882 left open.

New operations let an administrator export the data of a user without the user logging in, e.g. for an authority. They take the same credentials as getDataExportTask:

  • submitAdministrativeDataExportTask starts the export, with a mandatory case reference of at most 255 characters
  • getAdministrativeDataExportTask, cancelAdministrativeDataExportTask and deleteAdministrativeDataExportTask act on it
  • readAdministrativeDataExportPackage reads a result package in chunks of at most 4 MiB

A user has at most one administrative export, kept apart from the user's own; the user is not notified about it. Without a supplied mail credential, mail is exported through master authentication where com.openexchange.mail.admin.strategies lists master; otherwise mail is skipped, as is any module the user has no permission for. The task metadata gains origin, case reference, requested by and skipped modules, the result file metadata sha256. Submitting, downloading, canceling and deleting are logged to com.openexchange.gdpr.dataexport.auditTrail.

submitAdministrativeDataExportTask gains an overload with an AdministrativeMailCredential for the user's mailbox, used instead of master authentication: a password, ofPassword(masterUser, password), or an OAuth access token with optional refresh token, expiry and OpenID Connect back-end, ofOAuth(masterUser, accessToken, accessTokenExpires, refreshToken, oidcBackendPath, mechanism) with mechanism XOAUTH2 (default) or OAUTHBEARER. MW sends it through PLAIN or that mechanism with the user's mail login, whatever mail authentication is configured. Either may be a master user's: MW then logs in as <user's mail login><separator><master user> with com.openexchange.mail.admin.masterUserSeparator, so the administrator names the master user only, never the mailbox. For an OAuth master user, the Dovecot master passdb has to refuse non-master users with USER_DISABLED. The credential is kept encrypted in the mail credential vault for the lifetime of the export only, checked against the mail server on submit and never logged; mail is skipped if the mail server refuses it.

SCR-2146

Summary: New field sendAs in the deputy permission data objects of the RMI and gRPC interfaces

Effective: 8.55.481 and later

The RMI data objects com.openexchange.admin.rmi.dataobjects.DeputyPermission (and thereby ActiveDeputyPermission) and DeputyPermissionDescription carry the new boolean field sendAs, which lets the deputy send E-Mails as the granting user without a Sender header. The description object tracks it with the companion isSendAsSet flag, so an absent field keeps the current value on update.

The gRPC provisioning API mirrors it in deputy.proto: DeputyPermission.send_as (field 8) and the description pair sendAs (15) with SendAsSet (16).

Semantics match the SOAP interface: sendAs is mutually exclusive with sendOnBehalfOf (DEPUTY-0015), setting sendOnBehalfOf to false does not revoke sendAs, and com.openexchange.deputy.sendAsEnabled does not restrict administrative provisioning, but while it is disabled for the granting user, a grant of sendAs acts as sendOnBehalfOf (see SCR-2143). Apart from the missing Sender header, sendAs behaves like sendOnBehalfOf: a deputy permission granted to a group applies to every member (if the same deputy holds both forms from one granting user, e.g. directly and through a group, sendAs takes precedence), and com.openexchange.deputy.simplePermissionMode restricts neither form. The shared account interface OXSharedAccount keeps sendAs when it re-creates deputy permissions. Purely additive: the serialVersionUIDs of the data objects are unchanged, so RMI clients built against the previous version keep working, and the proto fields are wire compatible.

SCR-2142

Summary: New OXMailCredentialInterface method to search a context's kept mail credentials

Effective: 8.55.481 and later

OXMailCredentialInterface has the new method searchMailCredentials, which returns the new MailCredentialPage: the credentials found and the token of the next page. MailCredentialInfo has the new getUserId, which this and the other methods fill.

SCR-2116

Summary: Admin RMI calls for a context on another site report errors the client can load

Effective: 8.55.481 and later

In a multi-site deployment, OXMailCredentialInterface and OXMailFilterInterface forward a call for a context on another site over gRPC. An error from that site reached the RMI client as an UnmarshalException: the client cannot load the server-side exception class. Now the client gets the StorageException or InvalidDataException the other site reported, or a StorageException with its message. A user of a context on another site has to be given by its identifier; a user given by name only is rejected with an InvalidDataException instead of being looked up as user 0. Missing credentials for a context on another site are rejected with an InvalidCredentialsException instead of a NullPointerException; this applies to all provisioning RMI interfaces.

SCR-2107

Summary: New OXMailCredentialInterface methods to repair or refresh a kept mail credential

Effective: 8.55.481 and later

OXMailCredentialInterface has two new methods, repairMailCredential and refreshMailCredential. They take the same parameters as releaseMailCredential and return the new MailCredentialActionResult: the outcome and the credential as it stands afterwards. The outcomes match the operations RepairMailCredential and RefreshMailCredential of MailCredentialAdminService.

API - SOAP

SCR-2145

Summary: New element sendAs in the deputy permissions of the OXDeputyPermissionsService

Effective: 8.55.481 and later

The data objects DeputyPermission and ActiveDeputyPermission of the OXDeputyPermissionsService carry the new optional, nillable boolean element sendAs. It lets the deputy send E-Mails as the granting user, i.e. with the granting user as From and without a Sender header, as an alternative to sendOnBehalfOf.

The element is appended as the last element of both complex types, so the element sequence of the existing WSDL stays unchanged. It is accepted by the grant, grantMultiple and update operations and returned by get, list and, through the embedded ActiveDeputyPermission objects, by listGivenTo.

On update an absent element keeps the current value; setting sendAs or sendOnBehalfOf to true without passing the other one clears the other one. Passing both as true fails with a fault carrying DEPUTY-0015. Setting sendOnBehalfOf to false does not revoke sendAs; to revoke any sending right, pass both as false. The property com.openexchange.deputy.sendAsEnabled does not restrict this interface, but while it is false for the granting user, a grant of sendAs acts as "send on behalf of" (see SCR-2143). Existing SOAP clients are unaffected. Example grant request:

<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:Body>
    <soap:grant>
      <soap:deputyPermission>
        <xsd:userId>7</xsd:userId>
        <xsd:modulePermissions>
          <xsd:moduleId>mail</xsd:moduleId>
          <xsd:admin>false</xsd:admin>
          <xsd:folderPermission>2</xsd:folderPermission>
          <xsd:readPermission>4</xsd:readPermission>
          <xsd:writePermission>0</xsd:writePermission>
          <xsd:deletePermission>0</xsd:deletePermission>
        </xsd:modulePermissions>
        <xsd:folderMode>default</xsd:folderMode>
        <xsd:sendAs>true</xsd:sendAs>
      </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>

See the feature documentation for further details.

Behavioral Changes

SCR-2212

Summary: Enforced the Mail Permission Set of Shared Accounts for All Mail Operations

Effective: 8.55.481 and later

On the mail server, users of a shared account act as the shared account itself. So far, the mail permission set of a shared account permission was only reflected in the indicated own_rights, and checked for hard deletion and import. Now each mail operation is checked against the IMAP rights the permission set allows.

As a result, users with the viewer or editor permission set can no longer move, delete or archive mails, set \Deleted, expunge or clear folders, or copy mails into the shared account. Other flags and color labels remain settable. Users holding sendAs or sendOnBehalf still get the copies of the mails they send stored in the shared account's Sent folder. A refused deletion now reports IMAP-2006 instead of MSG-0070, for all mail accounts, not only shared ones.

No operator action is required; users who need to file away or delete mails need the author permission set. See the shared accounts documentation for how the permission sets map onto IMAP rights.

SCR-2207

Summary: Changed the resolution of a local time in the repeated hour at the end of daylight saving time

Effective: 8.55.481 and later

A local time that occurs twice because the clocks are set back, e.g. 02:30 on 25 October 2026 in Europe/Berlin, now refers to its first occurrence, still in daylight saving time, as RFC 5545 requires. Before, the middleware took the second occurrence, one hour later. This applies to date-times with a time zone in the HTTP API, to iCal and CalDAV imports and to the occurrences of recurring events. GregorianCalendarMetrics is patched for this in the repackaged bundle org.dmfs.rfc5545 (0.17.1-ox1-custom).

  • Events and occurrences in that hour that are created or saved again start one hour earlier. Existing change and delete exceptions keep matching their occurrences.
  • A series stored before whose start lies in that hour shows its first occurrence one hour before the stored series start.
  • Local times skipped at the start of daylight saving time are resolved as before.

No operator action is required.

SCR-2205

Summary: Restart the OpenID Connect login for a callback with an unknown or expired state

Effective: 8.55.481 and later

An authentication callback declined for an unknown or expired state restarts the login with a fresh authentication request instead of ending on an error page; with the session at the OpenID Provider still alive, the login completes without interaction. Restarts are bounded to three within two minutes per provider session, after which the callback fails as before, or lands at com.openexchange.oidc.failureRedirect if set.

  • com.openexchange.oidc.restartOnUnknownState, default true, reloadable, not config-cascade aware; false restores the previous behavior.

An expired authentication session reported by the OpenID Provider restarts the login the same way, at most three times for one flow; a callback whose token exchange failed keeps its state only for the remaining lifetime of the request.

SCR-2190

Summary: Weakforced connector sends session attributes with report requests and the requested host name with every request

Effective: 8.55.481 and later

The Weakforced connector now sends the session attributes configured through com.openexchange.weakforced.attributes with the report request as well. Every allow and report request also carries the attribute serverName, the host name the login request was addressed to, next to clientID. A policy can thus tell apart logins arriving through different host names, e.g. OIDC and form login. No admin action.

SCR-2187

Summary: The capability drive opens the Drive module to users without the infostore

Effective: 8.55.481 and later

In order to let a user work with other file storages than the built-in infostore, or with none yet, the capability drive now also entitles a user without the infostore permission to the Drive module: the Drive app and the folders of the user's file storages. So far it only enabled the OX Drive clients. A user with the infostore permission has the module as before, whatever the capability says; denying drive to such a user still keeps the OX Drive clients away only.

No change by default: the capability is still granted through contextSets/drive.yml to the users with the infostore permission only. Grant com.openexchange.capability.drive per context or user through the config cascade to a user who uses other file storages only, e.g. together with com.openexchange.file.storage.default pointing to an OpenCloud account.

See the feature documentation for further details.

SCR-2183

Summary: Changed Handling of Dropped Delete Exception Dates and Repeated Occurrence Deletes

Effective: 8.55.481 and later

Two changes that came with the calendar Trash folder apply to every user, whether or not the feature (com.openexchange.calendar.trashFolder.enabled) is switched on.

  • An update that drops a delete exception date of a series other people are on, i.e. makes the series produce that date again, puts the date in front of them once more: it becomes an overriding instance on which they are asked for an answer, announced by a request for that one date. This is the same step a restore from the Trash takes for a date going back into its series.
  • Deleting an occurrence the series already excludes is refused with CAL-4061 instead of being accepted again.

The third such change, the folder type of a shared account's calendars, is described in SCR-1988.

See the "Effects regardless of the setting" section of the calendar implementation details for further details.

SCR-2176

Summary: MCP server tools that write to Drive, and the OAuth scopes write_files and share_files

Effective: 8.55.481 and later

Drive now offers the OAuth scopes write_files and share_files; neither is granted by default. write_files opens the Drive write actions of the HTTP API to a token, deleting files and managing file storage accounts included. Sharing with others, that is permissions for other users, groups or guests, share links and notifications, takes share_files on top, because a share outlives the token that made it. Application passwords keep their configured scopes, so their write_files still shares. The MCP server /mcp offers file_create (write_files, a text or Markdown file of at most 512 KiB), mail_attachment_save (read_mail and write_files) and mail_draft_attach_file (write_mail and read_files), each listed only for a token that holds all its scopes and only where com.openexchange.mcp.write.enabled is true. They never overwrite or delete a file, never send mail, and need the confirmToken of a preview: true call. A 403 for an MCP tool now names the scopes the token lacks in error_description. No admin action unless writing is wanted.

SCR-2167

Summary: A Module Omitted When Setting Shared Account Permissions Falls Back to the Default Permission Set

Effective: 8.55.481 and later

setSharedAccountPermissions (RMI, SOAP, gRPC and SCIM) used to remove a module that was omitted for an entity, so a configured com.openexchange.sharedaccount.calendar.defaultPermissionSet or com.openexchange.sharedaccount.mail.defaultPermissionSet never applied to it. A module that is omitted, or supplied without permission level, now keeps its account and gets the configured default, as with createSharedAccountPermissions. Permissions read before can therefore be sent back unchanged, and the folder identifiers of a shared account stay the same when a permission set is revoked and granted again.

With the default none, access is unchanged. With a higher default, such entities now get it; to keep a module closed to some users, leave the default at none and grant permission sets explicitly, or lower the default for them through the config cascade, e.g. per context or user.

SCR-2166

Summary: Changing the IMAP Subscriptions of a Shared Account Requires the manageImapSubscriptions Capability

Effective: 8.55.481 and later

In order to prevent a single user from changing the visible mail folders of everyone else, changing the subscription status of a shared account's mail folder now requires the new shared account capability manageImapSubscriptions. The subscriptions belong to the shared account's mailbox, so a change applies to all of its users alike. Without the capability, the update is refused with MSG-0072. To users without it, the shared account's mail folders are indicated without the subscription bit (bit 4) in their capabilities, so that clients do not offer the change in the first place. Creating folders, and folder updates that only send the unchanged subscription status, are not affected.

The capability is not granted by default. After the update, nobody can change the subscriptions of a shared account until it is granted, either per shared account permission through provisioning (SOAP or command line), or to everyone through com.openexchange.sharedaccount.defaultCapabilities. Adding it there keeps the previous behavior.

See the feature documentation for further details.

SCR-2162

Summary: SSL white-list no longer exempts connections tunneled through a white-listed HTTP proxy

Effective: 8.55.481 and later

The SSL white-list (com.openexchange.net.ssl.whitelist) is no longer matched against the address of an HTTP proxy that tunnels a TLS connection (mail.<protocol>.proxy.host, https.proxyHost/https.proxyPort); only the target host name, or the target IP address if the host is configured by it, is matched. Before, with com.openexchange.net.ssl.trustlevel=restricted, every target reached through a proxy whose address was white-listed, by default any proxy on 127.0.0.1 or localhost, was accepted without certificate and host name verification.

  • Such connections are now verified like any other: a target with an untrusted or self-signed certificate behind such a proxy fails with SSL-0001 unless the target itself is white-listed.
  • If a TLS-intercepting proxy is in use, add its CA certificate to the custom trust store (com.openexchange.net.ssl.custom.truststore.enabled, com.openexchange.net.ssl.custom.truststore.path, com.openexchange.net.ssl.custom.truststore.password) instead of relying on the white-list.
  • Connections through SOCKS proxies and direct connections are unchanged.

SCR-2159

Summary: Drive Mail stores its attachments in the default file storage and applies auto-delete only where the storage deletes on its own

Effective: 8.55.481 and later

Drive Mail stores the attachments of a mail in the user's default file storage (see com.openexchange.file.storage.default) instead of a hard-wired infostore folder. Where that storage manages sharing links itself, as OpenCloud and Nextcloud do, the attachments are shared through a read-only link of the storage, created with the password and expiration date of the mail, and the mail carries that link; the share reference of such a mail holds no share token of the server. The expiration date of the mail expires the link.

The middleware does not delete data held by an external file storage, so for a user whose default storage is not the infostore the auto-delete option is neither applied nor forced, and com.openexchange.mail.compose.share.forceAutoDelete has no effect there. The new setting io.ox/mail//compose/shareAttachments/autoDeleteSupported tells clients whether the option is available, forceAutoDelete answers false where it cannot be honored.

No change for users whose default file storage is the infostore. See the feature documentation for further details.

SCR-2154

Summary: Removed Asterisk as Substitute for the @ Character in CalDAV and CardDAV Login Names

Effective: 8.55.481 and later

CalDAV and CardDAV no longer replace an asterisk (*) in the login name of a Basic authentication with an @ character. The substitution was introduced for very old macOS clients that could not enter an @ in the user name field, and is no longer needed. Clients still configured with a login like user*example.com need to switch to the regular login name, e.g. user@example.com. Along with this, the interface com.openexchange.tools.webdav.LoginCustomizer and its implementation AllowAsteriskAsSeparatorCustomizer have been removed from the bundle com.openexchange.server.

SCR-2150

Summary: Deputy permission updates routed to another site through gRPC apply their fields

Effective: 8.55.481 and later

In deployments with several sites, SiteAwareOXDeputyPermissions routes an administrative update of a deputy permission (OXDeputyPermissionsInterface.updateDeputyPermission) for a context of another site through the gRPC provisioning client. Its converter DeputyPermissionConverter.toProtoDeputyPermissionDescription did not set the *Set flags of entityId, group, sendOnBehalfOf, modulePermissions and folderMode. The receiving node applies flagged fields only, so it matched the stored deputy permission against entity 0 and rejected every such update with DEPUTY-0007 ("No such deputy permission").

The flags are now set, so such updates succeed and write what they carry, e.g. the module permissions are replaced by the ones passed and sendOnBehalfOf is applied. Provisioning scripts that ignored or retried the error will change deputy permissions from now on and should be checked. Updates of a context on the local site are not affected.

SCR-2149

Summary: Go entrypoint forwards termination signals to the middleware

Effective: 8.55.481 and later

With useLegacyBashScripts: false the Go entrypoint runs as PID 1. It now forwards SIGTERM, SIGINT, SIGHUP and SIGQUIT to the middleware, waits for it and exits with its exit code, or 128 plus the signal number if a signal ended it. Stopping a pod therefore shuts the middleware down gracefully within awaitShutDownSeconds instead of killing it, SIGQUIT prints a thread dump instead of ending the container, and orphaned processes are reaped. The default mode with tini is unchanged.

SCR-2138

Summary: Changed handling of secrets that cannot be obfuscated and of the contact trash clean-up at login

Effective: 8.55.481 and later

Secrets protected with the session obfuscation key are no longer stored or used in the wrong form. A login, a mail account change or another write fails with a retryable error instead of storing a password or token in plain text when it cannot be encrypted. While Argon2 key derivations are busy (CRP-0009), a request fails for now instead of using the still encrypted value as password, and such a session is read again on the next request instead of being kept with the wrong password. The removal of old contacts from the trash at login runs at most once per hour per user and node and removes at most 1000 contacts per run, reading only their identifiers and timestamps instead of loading all contacts in the trash.

SCR-2136

Summary: Changed timing of live change stream pings, session checks and presence

Effective: 8.55.481 and later

Live change streams now keep their pings on time regardless of Redis latency: the node timer only pings and hands session checks, token revalidation and mail watch renewal to background rounds, and stream presence is written to Redis in batches. Each distinct session is checked once every 30 seconds instead of every stream every 5 seconds, so a session ended on another node closes its streams within about 40 seconds plus two check rounds; a logout on the same node still closes them at once. While Redis or the identity provider is unavailable, one session or token is probed per pass and no stream is closed for that reason. The presence entries now expire after twice the ping interval plus 10 seconds. New metrics appsuite_pns_sse_tick_seconds and appsuite_pns_sse_checks_seconds report the duration of a timer pass and of a check round.

Streams are now also closed within seconds when their session is removed on another node: session removals are announced cluster-wide with a marker that nodes of older versions ignore, and the periodic session check remains as fallback. Closing takes about 5 to 8 seconds, the default buffering delay of Redis pub/sub.

The mailbox watcher for live changes no longer checks claims and sessions one after another on its timer. It does so in a bounded background round and checks a session at most every 30 seconds, so a slow or unavailable Redis no longer delays mail live changes or floods the log. A session that has ended may still be used to look at the mailbox for up to 30 seconds.

A live change stream request whose session still awaits its second factor is now answered with 401 and code second_factor_required instead of 503 with Retry-After. Failures that last, such as a mandatory second factor not set up yet or a token user who may not sign in, get 403 permission_denied. Only failures that may pass by themselves, e.g. of the session storage, keep 503 and their warning.

Streams of a node that went away without closing them, e.g. one that was killed, no longer count against com.openexchange.pns.transport.sse.maxConnectionsPerUser once the node's announcement in the new Redis hash ox-pns-sse-nodes expires after 15 seconds. When streams on other nodes exceed the limit, the oldest stream is closed about 20 seconds later instead of right away.

A node that holds maxConnectionsPerNode streams or shuts down answers further stream requests with 503 and a random Retry-After of 1 to 10 seconds instead of a fixed 30 seconds. Other temporary failures answer with a random 20 to 40 seconds.

A node holding more than 125% of the cluster's average number of streams, e.g. after a failover, moves streams to the other nodes. It closes at most 10% of them per minute with reason lifetime until it holds 110% of the average, and nothing moves while only one node is alive. If more than 75% of the moved clients come back to the same node, as behind a load balancer with session affinity, it pauses moving for 10 minutes, doubling up to an hour.

SCR-2135

Summary: Refresh kept OAuth tokens on use after a refresh without expires_in, and handle a refused client like an unusable credential

Effective: 8.55.481 and later

Kept OAuth tokens of the mail credential vault are refreshed on use when they expire within a minute. Where the identity provider left expires_in out of a refresh (RFC 6749 only recommends it), the new access token was kept with an unknown expiry and never refreshed on use again, so an expired token went to the mail server. Now the expiry is taken from the access token's exp claim where it is a JWT, otherwise from the lifetime of the token it replaces. Only where neither is known does it stay unknown.

A refresh the configuration does not allow was taken for a temporary failure: the identity provider answers invalid_client or unauthorized_client, e.g. after the client secret was rotated, or the OpenID Connect back-end the tokens name is no longer configured. Every use of an expired token failed with MCRED-0010, and a snoozed or scheduled mail waited silently, up to a week past its due date. Now such a use fails with the new code MCRED-0013. Snoozed and scheduled mail handle it like a refused credential: they go on through a live session of the user, or tell the user once that the mail waits for a login. The kept credential is neither rejected nor released, and push keeps it. The cause is logged on ERROR once an hour per back-end. MCRED-0010 remains for refreshes another node holds or that fail for now.

Live sessions go on with the tokens at hand, as before. TokenRefreshResponse.ErrorType gains CONFIGURATION and RefreshResult.FailReason gains CONFIGURATION_ERROR.

SCR-2134

Summary: Revoke access tokens only for mail password refusals that go on without a pause

Effective: 8.55.481 and later

Personal access tokens are revoked once the primary mail server keeps refusing the mail password a token keeps (com.openexchange.accesstoken.revokeOnRefusedPassword). Until now, any later refusal within the confirmation delay plus fifteen minutes confirmed the first one, even with no refusal in between. Without a live session of the user to tell a lockout from a changed password, two short lockouts about half an hour apart, e.g. provoked with failed logins, revoked the user's tokens. Where a live session tells that the password has changed, a refusal was confirmed up to 45 minutes later with the default delay, not five to fifteen minutes as documented.

Now the refusals have to go on: a pause of fifteen minutes without a refusal starts afresh. Tokens go after five minutes of refusals where a live session tells that the password has changed, and after com.openexchange.accesstoken.revokeOnRefusedPasswordWithoutSessionDelay (default 30 minutes) where none does. A client that tries less often than every fifteen minutes never confirms a refusal, as before. The cluster map mailRefusedCreds now holds the first and the latest refusal; nodes that still run an earlier version keep noting refusals on their own during a rolling upgrade.

SCR-2133

Summary: Repairing an exchanged mail credential no longer revokes the tokens it just obtained

Effective: 8.55.481 and later

When the mail credential vault repairs a credential kept with exchanged tokens, it no longer logs out the replaced tokens if they belong to the same back-end. Exchanges from the same SSO session share one client session at the identity provider. With Keycloak, revoking the replaced tokens also ended the client session of the new ones, and the next refresh was rejected. Replaced tokens now expire on their own; those of another back-end are still logged out. The documentation now states that exchanged tokens are logged out only together with the user's last exchanged credential for their back-end.

SCR-2132

Summary: Mail credential vault keeps credentials it cannot read for the moment and handles failed OAuth token refreshes

Effective: 8.55.481 and later

The mail credential vault no longer treats a mail credential as unreadable when it cannot read it only for the moment. Two cases were reported as unreadable before: no key derivation slot becoming free in time under load (CRP-0009), and a database failure while the maintenance job's walk after a change of com.openexchange.sessiond.encryptionKey reads or writes a row. Such a credential is no longer released from push or reported to its owner as unusable, and the walk does not finish until it has looked at it again.

The migration of legacy mail credentials keeps a credential when rewriting its row fails without a clear outcome, e.g. because the connection dropped before the commit was confirmed. It discards the credential only when the database rolled the rewrite back (lock wait timeout, deadlock) or the row now holds something else.

Kept OAuth tokens of the mail credential vault are refreshed on use when they expire within a minute. Where the identity provider left expires_in out of a refresh (RFC 6749 only recommends it), the new access token was kept with an unknown expiry and never refreshed on use again, so an expired token went to the mail server. Now the expiry is taken from the access token's exp claim where it is a JWT, otherwise from the lifetime of the token it replaces. Only where neither is known does it stay unknown.

A refresh the configuration does not allow was taken for a temporary failure: the identity provider answers invalid_client or unauthorized_client, e.g. after the client secret was rotated, or the OpenID Connect back-end the tokens name is no longer configured. Every use of an expired token failed with MCRED-0010, and a snoozed or scheduled mail waited silently, up to a week past its due date. Now such a use fails with the new code MCRED-0013. Snoozed and scheduled mail handle it like a refused credential: they go on through a live session of the user, or tell the user once that the mail waits for a login. The kept credential is neither rejected nor released, and push keeps it. The cause is logged on ERROR once an hour per back-end. MCRED-0010 remains for refreshes another node holds or that fail for now.

Live sessions go on with the tokens at hand, as before. TokenRefreshResponse.ErrorType gains CONFIGURATION and RefreshResult.FailReason gains CONFIGURATION_ERROR.

The new counter appsuite_mailcredential_refresh_misconfigured_total (tag refresh: use, keepalive) counts every refresh the configuration does not allow.

Where com.openexchange.oidc.opRevocationEndpoint is left empty, the middleware now takes the token revocation endpoint from the issuer's OpenID Connect discovery document (<opIssuer>/.well-known/openid-configuration, field revocation_endpoint). It is fetched on first use, cached for an hour, and used only if the document names the configured issuer and an https endpoint. A configured value still wins, and if discovery fails, exchanged tokens are left to expire as before.

The mail credential vault also logs a WARN (once a day per back-end) and counts appsuite_mailcredential_keepalive_too_late_total when a kept refresh token's own exp comes before its next keep-alive; lower com.openexchange.mail.credential.oauth.keepAliveInterval or use longer-lived refresh tokens in that case.

A busy key derivation for the former key during a change of com.openexchange.sessiond.encryptionKey no longer makes an intact credential unreadable. The keep-alive puts off credentials of a misconfigured back-end by one interval (new outcome misconfigured of appsuite_mailcredential_keepalive_total) and no longer ends its run for them, so they do not hold up healthy ones. Where another mail authenticator serves the user, the vault's authenticator leaves a credential that holds nothing for the mail login to that one. A mail data export retries a credential whose expired tokens cannot be refreshed for now (MCRED-0013) instead of failing at once. Exchanged tokens are left to expire while a live session of the same OpenID Connect back-end may share their client session, and released ones are logged out off the request thread.

A scheduled or snoozed mail whose kept credential is unusable falls back only to a session of its user that is alive at that time. Before, it could go out through the session it was scheduled or snoozed with, even after its user had logged out or an administrator had released the credential.

SCR-2129

Summary: OpenID Connect keeps refreshed tokens while the identity provider's signing keys cannot be fetched

Effective: 8.55.481 and later

When a token refresh returns a new ID token and the OpenID Connect provider's signing keys (JWK set, com.openexchange.oidc.opJwkSetEndpoint) cannot be fetched at that moment, the refreshed access and refresh tokens are now kept with the former ID token, and the next refresh checks the new one. Before, this counted as an invalid ID token: the user's session was ended, and the mail credential vault marked the kept credential as rejected, losing the tokens the identity provider had just issued. An ID token that fails the check (bad signature, unknown key, wrong issuer or audience, or another user) is still rejected.

SCR-2128

Summary: Mail credential vault keeps credentials it cannot read on a password change

Effective: 8.55.481 and later

On a password change, the mail credential vault no longer deletes kept mail credentials it cannot read at that moment; they keep the password from before the change. Previously it deleted them even when the cause was temporary, such as the session obfuscator being reloaded or a new com.openexchange.sessiond.encryptionKey configured before the former key was set as com.openexchange.sessiond.previousEncryptionKey. A credential that cannot be opened only for the moment is no longer treated as unreadable, and the maintenance job's walk after a key change does not finish until it has looked at it.

SCR-2126

Summary: Access tokens survive a provoked lockout and an unavailable session storage

Effective: 8.55.481 and later

Once the primary mail server refuses the password an access token keeps, the tokens are revoked within minutes only where a live session of the user shows that the password changed. Without a live session that logged in with a password, for example after someone provoked a directory lockout with failed logins, the refusal has to last com.openexchange.accesstoken.revokeOnRefusedPasswordWithoutSessionDelay (default 30 minutes) first. While the user's sessions cannot be looked up, e.g. because the session storage is unavailable, no token is revoked, the mail credential vault refreshes no kept OAuth tokens and repairs no rejected credentials; an administrator's repair answers failed then.

SCR-2125

Summary: Administrator's repair of a kept mail credential answers deferred while another node works on it

Effective: 8.55.481 and later

An administrator's repair of a kept mail credential (RepairMailCredential, POST …/mail-credentials/{credential_id}:repair, OXMailCredentialInterface.repairMailCredential) answers deferred while another node holds the credential and works on it. Before, it answered repaired although the credential was still rejected. A repair that lost the credential to another write that left it rejected now goes on with the next live session of the user instead of stopping.

SCR-2124

Summary: Mail credential vault no longer ties up pool threads when logging out the tokens of deleted users and contexts

Effective: 8.55.481 and later

When users or contexts are deleted, the mail credential vault logs out their exchanged tokens at the identity provider after the deletion is committed. Before, every deletion held a pool thread while waiting for one of four logout slots, so a mass deletion against a slow identity provider could take up the whole thread pool and stall the node. Now the logouts of all deletions wait in a node-wide queue of at most 20,000 rows and never hold a pool thread while waiting. Tokens of further deletions are left to expire at the identity provider, with one warning until the node has caught up.

SCR-2118

Summary: Releasing one exchanged mail credential no longer revokes the others

Effective: 8.55.481 and later

Mail credentials that the mail credential vault obtained through a token exchange share one client session at the identity provider when they were exchanged from the same SSO session. Revoking the tokens of one of them, e.g. when a snoozed mail returns or a credential is released over the provisioning API, ended that client session and the tokens of all the others. Those were rejected until a live session of the user repaired them. Now exchanged tokens are logged out only with the last exchanged credential of the user for the same OpenID Connect back-end; until then they are left to expire. Tokens exchanged for a credential that could not be stored are now logged out too, under the same rule. Two releases at the same time may both leave their tokens to expire.

SCR-2117

Summary: Legacy credential migration skips rows that are being handled and remembers walks that span several runs

Effective: 8.55.481 and later

The jobs that move the credentials of snoozed and scheduled mails written before the mail credential vault no longer rewrite a row while that mail is being returned, sent or unsnoozed; a later run moves it, unless its lock is older than a day. A walk through a table that spans several runs - e.g. because each run stops after twenty rows it cannot read - now counts as a walk: walked in mail_credential_migration is set when it ends and is negative while it is under way. Before, such a table was read and decrypted again every second run.

SCR-2113

Summary: Mail credential vault no longer presents an expired access token when the identity provider cannot be reached

Effective: 8.55.481 and later

If the identity provider could not be reached when a kept OAuth access token was due for a refresh, the vault presented the expired token to the mail server. The mail server rejected it as a bad credential: a returning snoozed mail told its owner that the kept credential was unusable, and push released the credential if the user had no live session. Now such a use fails with MCRED-0010 and is retried later. An access token that has not expired is still used as before. If refreshed tokens cannot be stored, they are used for that access instead of the expired ones. A refreshed access token the identity provider issues without an expiry no longer keeps the former token's expiry.

SCR-2112

Summary: Mail credential vault schedules kept tokens while the keep-alive is switched off

Effective: 8.55.481 and later

With com.openexchange.mail.credential.oauth.keepAliveInterval=0, the mail credential vault still schedules kept OAuth tokens, using the default interval. When the keep-alive is switched on again, the maintenance job takes up the credentials kept in the meantime; before, it never refreshed them. While the keep-alive is off, the gauge appsuite_mailcredential_rows_due reports zero and the provisioning API lists these credentials as not_kept_alive. The update task com.openexchange.mail.credential.impl.groupware.MailCredentialRefreshDueAfterSwitchOffTask schedules credentials that earlier releases left unscheduled, spread over the default interval.

SCR-2111

Summary: Front- and back-channel logout end a session again after the mail credential vault refreshed its tokens

Effective: 8.55.481 and later

When the mail credential vault refreshed tokens it keeps from a session, it mapped the identity provider's session (sid) to its own internal carrier instead of the user's session. A front- or back-channel logout at the identity provider then missed the user's session, which stayed logged in. The vault's refreshes no longer touch that mapping, so such a logout ends the user's session again.

SCR-2110

Summary: Mail credential vault refreshes a live session's tokens before a repair takes them over

Effective: 8.55.481 and later

When the mail credential vault repairs a kept credential with a live session's own OAuth tokens, it now refreshes those tokens at the identity provider first, except right after a login. Before, a session the identity provider had already ended passed its dead tokens to the credential, which then failed again at the next mail access. Now the refused refresh terminates that session, and the next live session of the user is tried. Each such repair costs one token refresh at the identity provider; concurrent repairs on several nodes make only one.

SCR-2109

Summary: Mail credential vault tries further live sessions when one cannot repair a credential

Effective: 8.55.481 and later

If a live session cannot repair a kept mail credential whose refresh token was rejected (e.g. a session the identity provider ended but that is still stored, whose tokens it no longer exchanges), the vault now tries the user's next live session, up to three, starting with those whose tokens were refreshed last. Before, it tried only the first session it found, and the credential stayed unrepaired until that session timed out. After a mail access fails to repair a credential, including when the repair itself fails, it waits a minute before trying again.

SCR-2108

Summary: Mail credential vault gauges report the cluster-wide count on every node

Effective: 8.55.481 and later

Every node now reports appsuite_mailcredential_rows_rejected and appsuite_mailcredential_rows_due as the count over all schemas, read from a cluster map that the maintenance job fills per schema. The gauges are registered at startup. Read the value from any one node; do not sum over the nodes. Without a cluster map, a node still reports only the schemas it ran the job for in the last 70 minutes. appsuite_mailcredential_repaired_total has the new trigger value admin; appsuite_mailcredential_keepalive_total uses it too, for refreshes an administrator requests.

SCR-2105

Summary: Access tokens keep the password for secret resolution under master authentication and OAuth mail access

Effective: 8.55.481 and later

Where com.openexchange.secret.secretSource contains <password>, an access token the middleware issues (a personal access token, a grant of the MCP authorization server or a Mobile API token) now keeps the minting session's password even where the mail login does not use it, i.e. under master authentication (com.openexchange.mail.passwordSource=global) or OAuth mail access. The password is sealed with the token's secret and serves secret resolution only, e.g. to open the stored password of an external mail account for a token with mail_external; it is never sent to a mail server. A token minted from a session without a password, such as a single sign-on session, keeps none, and its external accounts still answer OAUTHMAIL-0002; such deployments need a secret source without <password>. Tokens issued before this change keep no password; issuing a new one helps. No admin action.

SCR-2104

Summary: Mail credential vault repairs personal access token credentials on use and revokes exchanged tokens

Effective: 8.55.481 and later

A personal access token whose kept mail credential has a rejected refresh token is repaired the next time the token is presented, from a live session of its user; until then the token reaches no mail. Exchanged tokens that came without an ID token are revoked at the identity provider when their credential is released or expires, where com.openexchange.oidc.opRevocationEndpoint is set for the back-end. With Keycloak this ends only the exchanging client's session, not the user's.

SCR-2101

Summary: Access tokens reach the user's other mail accounts with the scope mail_external

Effective: 8.55.481 and later

The new OAuth scope mail_external lets an access token the middleware issues (a personal access token, a grant of the MCP authorization server or a Mobile API token) reach the user's secondary and external mail accounts. It widens what read_mail and write_mail reach and grants nothing on its own; users with webmail may grant it, and the MCP consent page offers it only to users with another mail account. Without it, such a token reaches the primary account only, and that now holds on every path: moving or copying a message into another account is refused with OAUTHMAIL-0001 as well. Secondary accounts log in with the token's kept credential. External accounts need the user's password to open their stored password where com.openexchange.secret.secretSource contains <password>, which a token minted under master authentication or OAuth mail access does not keep. No admin action.

SCR-2100

Summary: Mail credential vault keeps short-lived refreshed tokens, tells snoozed mail owners and reports more metrics

Effective: 8.55.481 and later

A refresh whose new access token expires within the refresh threshold of the OpenID Connect back-end (com.openexchange.oidc.oauthRefreshTime) no longer marks a kept mail credential as rejected. The new tokens are kept, a rotated refresh token included, and used while they last; a warning is logged at most once an hour.

The owner of a snoozed mail that waits for a login because its kept credential is unusable is told once through the notification queue. The notification goes once the mail is returned.

New metrics: the gauges appsuite_mailcredential_rows_rejected and appsuite_mailcredential_rows_due and the counter appsuite_mailcredential_shortlived_total.

SCR-2096

Summary: IMAP temporary-down back-off no longer triggered by account-specific failures after login

Effective: 8.55.481 and later

After a failed connect attempt, the middleware marks the IMAP server as temporarily down for com.openexchange.imap.imapTemporaryDown milliseconds and rejects all further connects to that server on the node with MSG-1016. A connection failure after the server accepted the credentials, such as a reset because a single mailbox is being migrated, no longer sets that mark: it only fails the affected request, other accounts are not blocked. Failures before authentication (connection refused or timed out, TLS handshake, greeting) set it as before. No admin action.

SCR-2095

Summary: Mail credential vault keeps more OAuth tokens alive and reports metrics

Effective: 8.55.481 and later

The mail credential vault keeps more OAuth tokens alive. Tokens without an ID token, e.g. from a token exchange, are now refreshed too. A personal access token's credential is kept alive when the token is presented, at most once an hour per token and without delaying the request. It is skipped while the session it was created in, or a copy of it, holds the same refresh token. A rejected credential is repaired from a live session that holds what mail access needs (tokens or a password), not from the first session found. New counters appsuite_mailcredential_* at /metrics count keep-alives by trigger and outcome, rejections, repairs, re-sealed and unreadable credentials.

SCR-2091

Summary: MCP server returns the text of PDF and office documents

Effective: 8.55.481 and later

The MCP server /mcp now returns the text of PDF and office documents (Word, Excel, PowerPoint, OpenDocument, RTF) through file_get, mail_attachment_get and the resource reads of files and attachments, cut at 4000 characters in tools and 100000 in resource reads. Office documents need the document converter. PDF files are read only where com.openexchange.mcp.documents.localPdf allows it. Without a converter, or when it fails, items are served as before: metadata in tools, bytes in resource reads. Documents above 5 MiB are not converted, a conversion is abandoned after 20 seconds, and each one takes one more permit of the user's tool call limit. The new bundle com.openexchange.mcp.documents.impl ships with open-xchange-mcp.

SCR-2090

Summary: Outgoing requests to user-supplied URLs check every address of the target host

Effective: 8.55.481 and later

Where the middleware fetches a URL that a user or client supplied (RSS feeds, iCal subscriptions, snippet images, vCard photos, mail auto-configuration, DAV subscriptions, web push and webhooks, the proxy servlet and MCP client metadata documents), it checks the target's address against the denied ranges. It now checks every address the host resolves to and connects to the address it checked, instead of checking one and letting the HTTP client resolve again. A host with any denied address is refused, which also blocks a second DNS record or a changed DNS answer that points inside. A connection no longer falls back to another address of the host; an IPv4 address is preferred. Through an HTTP proxy, a host that resolves locally is checked the same way, so a request the proxy would have carried to an internal address is now refused. A host that does not resolve locally is still left to the proxy.

SCR-2088

Summary: Mail credential vault keeps idle OAuth tokens alive and repairs rejected ones

Effective: 8.55.481 and later

OAuth tokens the mail credential vault keeps are now refreshed by an hourly job once they went unused for com.openexchange.mail.credential.oauth.keepAliveInterval (default 3D), so snoozed mail, scheduled mail and permanent push keep working past the identity provider's idle limit; set 0 where that limit is meant to cut off inactive users. A refresh token the identity provider rejects is marked and no longer presented; a live session of the user repairs the credential, at the latest on the user's next login. A credential that cannot be decrypted is no longer repaired from a live session, so that a copy of a personal access token's credential cannot outlive the token's revocation.

SCR-2084

Summary: New MCP server tools to read a conversation, find a meeting time and report what changed

Effective: 8.55.481 and later

The MCP server /mcp has three new read tools. mail_thread_get (scope read_mail) returns the conversation of a message, at most 50 messages, from its folder and the inbox and sent folder of its account. calendar_find_slot (scope read_calendar) proposes times when the user, up to 10 people and up to 5 rooms are all free, within the working hours the user set in App Suite; the find_meeting_slot prompt uses it. changes_since reports what changed since a point in time up to 31 days back: mail the inbox received, appointments created, changed or canceled, and tasks created, changed or completed, each part only where the token holds its read scope; the catch_up_on prompt starts with it. contacts_search now also finds contacts by the start of their company and, for queries with at least 5 digits, by phone number. No admin action needed; com.openexchange.mcp.tools.disabled switches single tools off.

SCR-2076

Summary: MCP briefing tool and daily briefing prompt

Effective: 8.55.481 and later

The MCP server /mcp offers briefing_get: what a day holds in the user's time zone, in one call. It lists the appointments, invitations awaiting an answer first; the unread inbox mail since the start of the previous working day, flagged first; the open tasks of the user's own folders due that day, then the overdue ones; and the reminders coming due by its end. Each section needs its read scope; one the token lacks is listed in omitted, so any token may call the tool. It only reads. The daily_briefing prompt now calls briefing_get instead of four tools and is listed for every token. No admin action.

SCR-2074

Summary: MCP tool results link into App Suite

Effective: 8.55.481 and later

Every mail, appointment, contact, task and file the tools of the MCP server /mcp return carries webUrl, a link that opens the item in App Suite. The link uses the host the client reached the server on, resolved per context as for share links, and the UI path com.openexchange.UIWebPath. An occurrence of a series is linked with its recurrenceId. No admin action.

SCR-2073

Summary: MCP server tools that change mail, the vacation notice and mail filter rules, and output schemas for all tools

Effective: 8.55.481 and later

The MCP server /mcp offers mail_draft_create, mail_mark, mail_move, mail_delete, mail_folder_create, mail_folder_rename, mail_send, vacation_set, mailfilter_create, mailfilter_update and mailfilter_delete, listed and callable only where com.openexchange.mcp.write.enabled is true and the token holds write_mail; mailfilter_list reads the rules with read_mail. mail_delete moves messages to the trash and never deletes for good. mail_send sends a draft from the drafts folder; while com.openexchange.mcp.write.externalAttendees is false, every recipient has to be a user of the context, and vacation_set takes no new text for a notice that replies to every sender. Filter rules can move, flag, mark read, move to the trash and stop; a rule that forwards can only be switched off. Every write needs the confirmToken of a preview: true call, which does not prove that a person saw the preview. com.openexchange.mcp.tools.disabled=mail_send turns off sending alone. No admin action unless writing is wanted.

mail_send now hands a confirmed draft to scheduled mail where the user can schedule mails: it goes out after com.openexchange.mcp.mail.sendDelay seconds, 60 by default, or at the time given in sendAt, and mail_scheduled_cancel or App Suite can stop it until then. The new tools mail_scheduled_list and mail_snoozed_list (read_mail) list the user's scheduled and snoozed mails; mail_scheduled_cancel, mail_snooze and mail_unsnooze (write_mail) stop a scheduled mail and snooze or return mails as App Suite does, each confirmed like every other write. Mails held this way count toward com.openexchange.mail.scheduled.maxNumberOfScheduledMailsPerHour (100 by default); raise it where users let an assistant send more.

From protocol revision 2025-06-18 on, tools/list gives every tool an outputSchema, a JSON Schema of its structuredContent; under 2025-03-26 the list is unchanged.

SCR-2071

Summary: Built-in OAuth authorization server for the MCP server

Effective: 8.55.481 and later

Update Task com.openexchange.accesstoken.impl.groupware.AccessTokenAddGrantColumnsTask

com.openexchange.accesstoken.impl.groupware.AccessTokenGrantCreateTableTask

With com.openexchange.mcp.oauth.enabled the middleware acts as OAuth 2.0 authorization server for /mcp, so that a client implementing the MCP authorization spec, such as claude.ai, ChatGPT or VS Code, connects with the endpoint URL alone. The App Suite origin is the issuer: it serves /.well-known/oauth-authorization-server, dynamic client registration at /oauth/register, the code flow with PKCE at /oauth/authorize, and /oauth/token and /oauth/revoke; route /.well-known/oauth-authorization-server and /oauth/ to the middleware like /mcp. The user signs in through the regular login, so second factor and single sign-on work unchanged, and confirms the scopes on a consent page the middleware serves; write scopes are never preselected. On the same page the user can limit the grant to some folders per module, subfolders excluded; every token of the grant keeps the restriction. The client gets oxa_ access tokens valid for an hour and a refresh token that rotates on every use; presenting a replaced refresh token revokes the grant. Grants appear in the access token list; a password change revokes them all. An external authorization server stays first in authorization_servers. The new table access_token_grant and the new columns grant_id and grant_key of access_token are added by update tasks. A client can also skip registration and name itself by the https URL of a client ID metadata document, as Claude Code does: the middleware fetches that document directly, never from a non-public address, and caches it for at most an hour. For such URLs, an update task widens the column client_id of access_token_grant from 64 to 255 characters. The server's pages appear in the user's language, or before sign-in the browser's, where a translation exists; otherwise in English.

SCR-2070

Summary: MCP server tools that change tasks and contacts

Effective: 8.55.481 and later

The MCP server /mcp offers task_create, task_update, task_complete, contact_create and contact_update. They are listed and callable only where com.openexchange.mcp.write.enabled is true and the token holds write_tasks or write_contacts. As with the calendar tools, a call writes only with the confirmToken of a preview: true call with the same arguments. Nobody gets mail from these changes. Contacts can be written in any address book the user may write, except other users' entries in the global address book. task_get and contact_get now report the timestamp these tools take for optimistic locking. No admin action unless writing is wanted.

SCR-2066

Summary: Middleware keeps no sessions of its own when external authentication is enabled

Effective: 8.55.481 and later

While com.openexchange.external.authentication.enabled is true, the middleware resolves every request from the JWT the external authentication service issues and keeps no session of its own:

  • the Redis session store does not register; com.openexchange.sessiond.noop provides a session service that stores nothing
  • the login servlet (/ajax/login), the SOAP session service and the sessionmanagement module are not registered - login and session management are offered by the external service
  • share and guest links, including password-protected links and the guest password reset, are resolved through the external service; a failed share request is answered with a redirect instead of a bare error
  • the OpenID Connect flow creates no session but redirects to com.openexchange.external.authentication.oidc.handoffRedirectURL
  • DAV and the DAVx5 onboarding authenticate via the bearer token
  • an internal App Suite service forwarding an already authenticated request may name the acting client in the header X-OX-Client-Override; the header is ignored without external authentication
  • personal access tokens are issued by the external service: the accesstoken module of the HTTP API and the capability access_tokens are not registered

With external authentication disabled (the default) the behavior is unchanged.

SCR-2061

Summary: Address Books Can Be Shared Across Context Boundaries

Effective: 8.55.481 and later

Address books can now be shared to users of other contexts, like calendars and mail folders, subject to the cross-context trust zones. The grantee sees them as foreign address books, over the HTTP API and CardDAV.

  • A foreign grantee receives at most author rights, and needs contacts and groupware access.
  • Contacts flagged private are not shared across contexts.
  • A contact deleted by a foreign grantee goes into the trash folder of the address book's owner.
  • Foreign address books take part in searches and synchronization. CardDAV exposes them once the grantee enables them for synchronization.
  • An address book shared by e-mail address to a user of another context becomes a cross-context grant instead of a guest share, as for calendars.

See the feature documentation for further details.

SCR-2054

Summary: MCP server tools that change calendar appointments and reminders, and confirming writes with the user

Effective: 8.55.481 and later

The MCP server /mcp offers calendar_create_event, calendar_update_event, calendar_respond, calendar_delete_event and calendar_set_reminder. They are listed and callable only where com.openexchange.mcp.write.enabled is true and the token holds write_calendar, which a client has to ask for explicitly: a 401 challenge from /mcp names the read scopes only. Each tool takes preview: true, which reports the change, conflicts and recipients without saving anything, and returns a confirmToken; the tool writes only when called again with that token and exactly the previewed arguments, within five minutes and before the object changes. Appointments are scheduled as in App Suite, iTIP mail included. calendar_set_reminder sets or removes the user's own reminder of an appointment or one occurrence and sends no mail. calendar_get_event reports the timestamp these tools take for optimistic locking. No admin action unless writing is wanted.

Where a request of protocol revision 2026-07-28 declares the client capability elicitation with form mode, the user confirms every MCP write, not only those of the calendar tools: a call without preview is answered with resultType: "input_required", a question that says what the call would do, and a requestState. Only the client's retry with the user's accept and that state writes; decline and cancel end as the tool errors confirm_declined and confirm_canceled. With such a client a confirmToken alone no longer confirms a write. Clients without the capability and the earlier protocol revisions keep the preview and confirmToken flow. No admin action.

SCR-2050

Summary: Composition spaces in the database or file storage are encrypted with AES/GCM

Effective: 8.55.481 and later

Composition spaces kept in the database or file storage (com.openexchange.mail.compose.mailstorage.enabled set to false) with com.openexchange.mail.compose.security.encryptionEnabled set to true were encrypted with AES/CBC, a fixed IV and no integrity protection: identical content produced identical ciphertext, and altered data went undetected. New content and attachments are now encrypted with AES/GCM and a random IV; attachments are sealed in 16 KiB segments. Existing data stays readable. The default draft-based storage is not affected.

Nodes on 8.46 to 8.54 read the new format only from the patch release that includes this change. Update them to that patch release before a rolling update to 8.55, and do not downgrade below it afterwards; otherwise composition spaces written by 8.55 cannot be opened.

SCR-2048

Summary: User pseudonyms in exported feedback are keyed by a secret

Effective: 8.55.481 and later

Exported NPS and star rating feedback identifies users by a pseudonym. It was an MD5 hash of context and user ID, which anyone can trace back by hashing all IDs. It is now an HMAC-SHA256 keyed by com.openexchange.userfeedback.pseudonym.secret, so pseudonyms change once with the update and cannot be linked to earlier exports. Set the same secret on all nodes to keep pseudonyms stable across nodes and restarts.

SCR-2047

Summary: Invalid SSL trust level and missing trust stores no longer trust every certificate

Effective: 8.55.481 and later

An invalid value for com.openexchange.net.ssl.trustlevel (for example the typo restriced) now falls back to restricted instead of all, so certificates are validated; the error log names the fallback. If restricted is set but the JVM's default trust store is disabled via com.openexchange.net.ssl.default.truststore.enabled and no custom trust store is configured, Redis, S3, JMAP and Cassandra clients now validate against the JVM's default trust store instead of trusting every certificate. Valid values, including the default all, are not affected. If connections to self-signed endpoints fail after the update, check the configured trust level.

For JMAP, com.openexchange.jmap.trustAll now defaults to false: a TLS connection without an X509 trust manager is refused instead of trusting every certificate. With com.openexchange.jmap.requireTls set to true, which is the default, a JMAP server addressed via plain HTTP is now refused with error code JMAP-0017; deployments that reach their JMAP server via HTTP need to set com.openexchange.jmap.requireTls (or its primary. / secondary. variant) to false. The OX session (com.openexchange.jmap.oxSessionAuth) is now only forwarded to the JMAP server configured for the primary or a secondary account, never to a server of an account a user added; for such an account, requests to other hosts named in the server's session document must reach a public address.

SCR-2040

Summary: White-Listed Hosts Are Exempt From Host Name Verification

Effective: 8.55.481 and later

In order to allow the restricted trust level (com.openexchange.net.ssl.trustlevel=restricted) for internal services presenting a certificate issued for other host names, e.g. a mail server reached through a cluster-internal service name, hosts covered by com.openexchange.net.ssl.whitelist are now also exempt from the host name verification performed after the TLS handshake. Previously, the white-list only skipped the certificate checks of the trust managers, so connections to such hosts still failed while com.openexchange.net.ssl.hostname.verification.enabled was set.

The exemption applies to connections opened through the middleware's TLS socket factory, i.e. mail connections and HTTP clients without a TLS setup of their own, and only with the restricted trust level. The default white-list only covers loopback addresses and localhost. See the property documentation for further details.

The white-list also no longer resolves host names: a host name entry matches the name used to connect, an address entry the address a connection actually goes to. Previously, a host name was accepted as soon as any address of its DNS answer was white-listed, so a crafted DNS answer could skip the certificate checks. The white-list now also applies to Redis, Cassandra and the asynchronous S3 client; for these, an address entry only matches a host configured by that address.

SCR-2015

Summary: Move Contacts Deleted From Shared Folders Into the Owner's Trash

Effective: 8.55.481 and later

Contacts soft-deleted from a shared folder now go into the trash folder of the folder's owner, not the deleting user's. The owner's com.openexchange.contact.trashFolder.enabled setting applies, and the owner can restore them. Public folders are unchanged.

The deleting user can still undo the deletion: the undo now addresses the source folder. Accordingly, the restore action of the addressbooks and contacts modules also accepts the source folder and restores exactly the contacts the acting user deleted from it, provided they may still create contacts there.

See the contact trash folder documentation for further details.

SCR-1945

Summary: New MCP server endpoint for read-only access to mail, calendar, contacts, files and tasks

Effective: 8.55.481 and later

The middleware offers a Model Context Protocol server at /mcp (protocol revision 2026-07-28 and, over the same endpoint, the initialize handshake of revisions 2025-03-26, 2025-06-18 and 2025-11-25, which clients such as claude.ai connectors speak: no session identifier is issued, ping is answered, an unknown method is a JSON-RPC error on 200, and the mirroring headers are optional there, stateless HTTP POST) with read-only tools, prompts and resources. The tools are me_get, mail_search, mail_get, mail_attachment_get, calendar_list_events, calendar_get_event, calendar_free_busy, resources_search, contacts_search, contact_get, users_search, files_search, file_get, tasks_search, task_get, vacation_get, reminders_list and a folder tool per module (mail_folders, calendar_folders, contacts_folders, files_folders, tasks_folders); every list result can be paged through an opaque cursor argument and the nextCursor it returns. The prompts daily_briefing, inbox_triage, find_meeting_slot and catch_up_on chain those tools and are offered only where every tool they drive is available to the caller. Resources are read by URI through the templates ox:///files/{id}, ox:///mail/{folder}/{id} and ox:///mail/{folder}/{id}/attachment/{attachment}, as text, marked in _meta when it was cut, or, for anything without a text form, as its bytes up to 5 MiB, refusing a larger one with -32602 rather than cutting it; resources/list enumerates nothing. Callers authenticate with a bearer token that the OAuth provider validates, either a JWT from the configured authorization server or a personal access token; tools and resources are visible and usable only with the scopes read_mail, read_calendar, read_contacts, read_files, read_tasks and read_reminders, while me_get is open to every valid token. /.well-known/oauth-protected-resource/mcp serves the RFC 9728 resource metadata. Tool calls and resource reads are rate-limited per user, bounded in how many of one user run at once on a node, and written as one audit line each at level INFO through the logger com.openexchange.mcp.protocol.McpRequestHandler, without argument values or content, and measured through the meters appsuite.mcp.requests, appsuite.mcp.tool.calls and appsuite.mcp.authentications; the core-mw Grafana dashboard gained an MCP row. A bundle that still waits for a needed service, typically the OAuth provider, logs a warning naming it a minute after start. An OpenAPI document describing both paths, the transport headers, every method, the tools, prompts and resources is published as mcp.openapi.json under components/middleware/mcp/<version>/ next to the SCIM and provisioning documents. The endpoint is off by default and needs the chart feature mcp, com.openexchange.mcp.enabled=true and an enabled OAuth provider (com.openexchange.oauth.provider.enabled). The mail tools reach the primary mail account only; secondary and external accounts, which keep their own credentials, are outside a token session's reach. Documentation: documentation/administration/mcp_server.md.

Arguments that do not match a tool's input schema are answered as a tool result with isError on revisions 2025-11-25 and 2026-07-28, so that the model can correct the call; 2025-03-26 and 2025-06-18 keep the JSON-RPC error -32602. A tool call beyond the per-user rate limit or in-flight bound is a tool result with isError and Retry-After, a resource read beyond it a 429 carrying a JSON-RPC error. A valid token whose user may not use the endpoint (the capability mcp is checked on every request) or cannot sign in, such as a disabled user or context, is answered with 403 without a challenge; a token that cannot be checked right now, with 503 and Retry-After. A JSON-RPC batch is refused with -32600, and the earlier revisions answer a missing resource with -32002. Every tool carries annotations that mark it read-only. calendar_list_events covers every subscribed calendar the user sees across accounts and gives the user's participation status as myStatus; tasks_search gives all-day tasks as dates; vacation_get tells whether the notice replies today and its date range; reminders_list names the occurrence of a series; mail_search without a query lists the newest messages; users_search no longer fills in an e-mail address the address book withholds. A JWT can be tied to the endpoint through com.openexchange.mcp.audience (SCR-2027).

A request body has to hold exactly one JSON object; anything else is refused with 400 and -32700, a charset no runtime knows with 415. A nextCursor continues only the list it was handed out for: the same tool with the same arguments apart from cursor and limit. calendar_folders and contacts_folders list calendars and address books by the identifiers the calendar and contact tools report and take, such as cal://0/31 and con://0/32. calendar_list_events tells through calendar whether an event was read through the user's own, a shared or a public calendar. List results carry partial and warnings where a calendar, address book or folder could not be read, instead of failing or looking complete. mail_get joins every inline text part of a message and no longer lists inline images as attachments; a text file declared as application/octet-stream is served as text. For a caller without read access to the global address book, users_search matches names only and reports time zone and language for the caller alone. task_get, like the get action of the tasks module, refuses someone else's task in a folder where the caller may read only their own objects. Resource reads are measured through appsuite.mcp.resource.reads.

CLT

SCR-2200

Summary: New options --recoveryemail, --recoveryphone and --recoverypin for createuser and changeuser

Effective: 8.55.481 and later

  • \-\-recoveryemail sets the recovery email address.
  • \-\-recoveryphone sets the recovery phone number, in international format with a leading \+.
  • \-\-recoverypin sets the recovery PIN.

An empty string clears a value. An omitted option leaves it unchanged.

SCR-2178

Summary: listdataexports and dataexportconsistency check the administrator credentials; new tools submitdataexport and downloaddataexport

Effective: 8.55.481 and later

The command-line tools listdataexports and dataexportconsistency always asked for -A/-P, but the server did not check these credentials. It now does:

  • listdataexports -c <contextId> accepts the context administrator, the master administrator only where MASTER_ACCOUNT_OVERRIDE is enabled
  • listdataexports without -c and dataexportconsistency require the master administrator

Scripts that call these tools with wrong credentials, or list all data exports as context administrator, now fail with an authentication error.

New tools handle an export an administrator starts on behalf of a user:

  • submitdataexport starts it for the given modules and a mandatory case reference
  • downloaddataexport downloads all packages, verifies each against its SHA-256 checksum and, with --delete, deletes the export once every package is verified
  • listdataexports -a and canceldataexports -a show and cancel it; the listing includes skipped modules and checksums

Examples:

# Data exports of context 1234, as its context administrator
listdataexports -c 1234 -A oxadmin -P secret

# Data export of user 3 in context 1234, including work items and result files
listdataexports -c 1234 -i 3 -A oxadmin -P secret

# All data exports - master administrator only
listdataexports -A oxadminmaster -P secret

# Orphaned entries of file storage 34 - master administrator only
dataexportconsistency -f 34 -A oxadminmaster -P secret

# Export mail and calendar of user 3 in context 1234 for case AZ 4711/26
submitdataexport -c 1234 -i 3 -m mail,calendar -r "AZ 4711/26" -A oxadmin -P secret

# Show that export, then download, verify and delete it
listdataexports -c 1234 -i 3 -a -A oxadmin -P secret
downloaddataexport -c 1234 -i 3 -o /var/tmp/case-4711 --delete -A oxadmin -P secret

The underlying RMI change is described in SCR-2177.

submitdataexport takes a credential for the user's mailbox, used instead of master authentication. Secrets are read from files, - for standard input, so that they show up neither in the process list nor in the shell history:

  • --mail-password-file, or --mail-access-token-file with --mail-access-token-expires, --mail-refresh-token-file, --mail-oidc-backend and --mail-oauth-mechanism (XOAUTH2 default, or OAUTHBEARER)
  • --mail-master-user if the password or token is a master user's; MW composes the login from the user's mail login and com.openexchange.mail.admin.masterUserSeparator
# Mail through the master user "exporter", the password read from standard input
submitdataexport -c 1234 -i 3 -m mail,calendar -r "AZ 4711/26" --mail-master-user exporter --mail-password-file - -A oxadmin -P secret
# Mail through an OAuth access token of the user, sent through OAUTHBEARER
submitdataexport -c 1234 -i 3 -m mail -r "AZ 4711/26" --mail-access-token-file - --mail-oauth-mechanism OAUTHBEARER -A oxadmin -P secret

Changed defaults

SCR-2152

Summary: Changed defaults for SMTP pipelining and chunking

Effective: 8.55.481 and later

The SMTP transport now uses command pipelining and plain DATA by default, which saves round trips when sending mail.

  • com.openexchange.smtp.enablePipelining If the SMTP server announces PIPELINING, the MAIL FROM and RCPT TO commands are sent without waiting for each reply. Set to false to restore the previous behavior. Unset com.openexchange.smtp.primary.enablePipelining and com.openexchange.smtp.secondary.enablePipelining follow this value. Default true (was false). Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.smtp.chunksize Message data is now sent with DATA instead of BDAT chunks, even if the server announces CHUNKING. Set to 131072 to restore the previous behavior. Unset com.openexchange.smtp.primary.chunksize and com.openexchange.smtp.secondary.chunksize follow this value. A value less than or equal to 0 (zero) disables chunking. Default 0 (was 131072). Reloadable, config-cascade aware. No dedicated properties file.

SCR-2056

Summary: Changed default of com.openexchange.mcp.instructions

Effective: 8.55.481 and later

The default of com.openexchange.mcp.instructions, the guidance MCP clients pass to their model, no longer calls the server read-only and asks the model to preview changes and confirm them with the user. Deployments that set their own text should check it before they set com.openexchange.mcp.write.enabled to true.

Configuration

SCR-2210

Summary: New configuration option for pooled mail credentials

Effective: 8.55.481 and later

The mail credential vault can let the features of a user share the credential they keep from the same login.

  • com.openexchange.mail.credential.pooling Whether permanent push, snoozed and scheduled mail and the data export refer to one pooled credential per user and login, told apart by the session at the identity provider and by the password, instead of keeping one each. The pooled credential is refreshed, kept alive, repaired and rewritten on a password change once for all of them. Exchanged tokens, the offline grant, credentials of personal access tokens and credentials an administrator supplied stay a feature's own. A credential that refers to a pooled one keeps a copy, updated with every change of the pooled one, which earlier versions use as a credential of their own: nodes of both versions can run side by side, and going back needs no preparation. Credentials kept before are pooled on their next use; switched off, the maintenance job gives every one its own credential back. Default true. Reloadable, config-cascade aware. No dedicated properties file.

SCR-2206

Summary: New configuration option for keeping the Sieve capabilities of a user

Effective: 8.55.481 and later

New configuration option for the connection to the Sieve end-point of the mail filter.

  • com.openexchange.mail.filter.capabilitiesCacheIdleTime Specifies how long, in milliseconds, the capabilities that the Sieve end-point advertises to an authenticated user are kept after their last use. While they are kept, querying the mail filter configuration needs no connection to the Sieve end-point. A value of 0 (zero) means not to keep them. Default 0. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2204

Summary: New property com.openexchange.oidc.stateLifetimeSeconds for pending OpenID Connect logins

Effective: 8.55.481 and later

The lifetime of a pending OpenID Connect authentication request, i.e. how long its state, nonce and PKCE code verifier are remembered before a callback is declined, is now configurable instead of fixed to five minutes.

  • com.openexchange.oidc.stateLifetimeSeconds, default 1800, reloadable, not config-cascade aware, settable per backend.

The default matches Keycloak's login timeout of 30 minutes; align it with the identity provider in use. No operator action is required.

SCR-2202

Summary: New Property com.openexchange.undo.maxTimeToLive Limits the Lifetime of Undo Operations

Effective: 8.55.481 and later

The new property com.openexchange.undo.maxTimeToLive limits how long an undoable operation of the HTTP API can be undone, in milliseconds. The period is chosen by the client through the undo parameter, which so far was taken over without any bound for the undoable actions of the modules mail, contacts, folders and chronos. A longer period is now capped at the configured value, while the operation itself is still performed as requested.

It defaults to 300000 (five minutes), is reloadable and config-cascade aware. A value of 0 or below removes the limit, which restores the previous behavior. No operator action is required, as App Suite UI asks for at most 70 seconds. See the configuration documentation for further details.

SCR-2195

Summary: New properties com.openexchange.passwordchange.admin.* for administrative password changes by database or webhook

Effective: 8.55.481 and later

Account recovery changes the password through a new administrative password-change layer that works without a user session. Two backends ship:* database is active while the database authentication service is registered. It writes the users table and ends the user's sessions. * webhook calls a configured endpoint.

With neither backend active, the reset answers 503.

Backend selection:

  • com.openexchange.passwordchange.admin.\[providerId\].enabled, for example com.openexchange.passwordchange.admin.webhook.enabled

Password policy of the database backend:

  • com.openexchange.passwordchange.admin.minLength
  • com.openexchange.passwordchange.admin.digitRequired
  • com.openexchange.passwordchange.admin.lowerCaseRequired
  • com.openexchange.passwordchange.admin.upperCaseRequired
  • com.openexchange.passwordchange.admin.specialCharRequired

Webhook backend:

  • com.openexchange.passwordchange.admin.webhook.endpoint
  • com.openexchange.passwordchange.admin.webhook.username
  • com.openexchange.passwordchange.admin.webhook.password, which belongs in the secret properties
  • com.openexchange.passwordchange.admin.webhook.httpsOnly

Any password change revokes the user's open reset links, provisioning included. Deleting the user revokes them as well.

SCR-2194

Summary: New properties com.openexchange.accountrecovery.* configure self-service account recovery

Effective: 8.55.481 and later

New lean configuration properties for the account recovery feature. All of them are config-cascade aware, except com.openexchange.accountrecovery.enabled.

Switch and links:

  • com.openexchange.accountrecovery.enabled switches the feature on. It defaults to false, applies server-wide and is read at bundle start.
  • com.openexchange.accountrecovery.api.resetUrl sets the page the reset link opens. Without it the link opens <host>/appsuite/?login\_type=set\_password. Links never use the request's host.
  • com.openexchange.accountrecovery.api.verifyUrl sets the page the verification link opens.

Limits:

  • com.openexchange.accountrecovery.api.rateLimit limits requests per minute per address and per matched user, default 5. It also limits each caller of the admin REST endpoints. 0 or \-1 disables it.
  • com.openexchange.accountrecovery.api.rateLimitPerClient limits requests per minute per client address, default 20.
  • com.openexchange.accountrecovery.api.maxOutstandingTokensPerUser limits unexpired tokens per user, default 2.
  • com.openexchange.accountrecovery.api.maxMatchesPerRequest limits the users that get a link per request, default 10.
  • com.openexchange.accountrecovery.api.tokenLifetimeMinutes sets the lifetime of a reset link in minutes, default 60.

Notification channels:

  • com.openexchange.accountrecovery.notify.request.primary\-email
  • com.openexchange.accountrecovery.notify.request.backup\-email
  • com.openexchange.accountrecovery.notify.request.sms
  • com.openexchange.accountrecovery.notify.reset.primary\-email
  • com.openexchange.accountrecovery.notify.reset.backup\-email
  • com.openexchange.accountrecovery.notify.reset.sms

Sender and phone numbers:

  • com.openexchange.accountrecovery.mail.senderName
  • com.openexchange.accountrecovery.mail.replyTo
  • com.openexchange.accountrecovery.phone.defaultRegion

Verification of recovery contacts:

  • com.openexchange.accountrecovery.verification.requireVerifiedEmail
  • com.openexchange.accountrecovery.verification.requireVerifiedPhone
  • com.openexchange.accountrecovery.verification.emailLinkTtlMinutes
  • com.openexchange.accountrecovery.verification.smsCodeTtlMinutes
  • com.openexchange.accountrecovery.verification.smsCodeMaxAttempts
  • com.openexchange.accountrecovery.verification.smsCodeLength

The feature also reads the existing property com.openexchange.mailmapping.lookUpByDomain. With the default false, only recovery addresses lead to a token. Resolving a primary address would query every schema per request.

SCR-2191

Summary: New Properties to Let Users Allow Background Mail Access Through Their OpenID Connect Login

Effective: 8.55.481 and later

Users who log in through OpenID Connect can allow background mail access once: an authorization code flow with the offline_access scope, whose tokens the mail credential vault keeps as the user's offline grant. Features that keep mail credentials in the vault can refer to that grant instead of keeping a credential of their own, so they work without master authentication or a token exchange; in this version, scheduled and snoozed mail do. Until the user has allowed it, such a feature fails with MCRED-0014, which App Suite UI takes as its cue to ask.

  • com.openexchange.oidc.offlineGrantEnabled lets the users of the back-end allow it and registers the end-point offline_grant. Defaults to false; read when the back-end starts, so not reloadable.
  • com.openexchange.oidc.offlineGrantScope is requested in addition to openid and the login's scope. Defaults to offline_access, reloadable.
  • com.openexchange.oidc.offlineGrantPrompt sets an optional prompt for the identity provider, e.g. consent. Empty by default, reloadable.
  • com.openexchange.oidc.offlineGrantAdditionalParameters adds further parameters to the authorization request. Empty by default, reloadable.
  • com.openexchange.mail.credential.oauth.offlineGrantIdleTime releases a grant once it has gone unused this long. Defaults to 90D (0 keeps it until revoked); reloadable and config-cascade aware.

The OpenID Connect properties may be set per back-end, e.g. com.openexchange.oidc.<backend>.offlineGrantEnabled. A configured token exchange takes precedence. A feature refers to the grant only where it gets along with the grant's tokens, which the mail server may narrow to the folders the feature works on; features that read the user's mail, such as push or the data export, keep their own credentials. The administrative listing of kept credentials shows a grant with the kind offline, and the credentials referring to it with the kind delegated. Nodes of an earlier version cannot read what the vault keeps for a grant, so enable it only once every node runs this version. Nothing changes as long as offlineGrantEnabled is not set.

See the Background Mail Access article for the setup of middleware, identity provider and mail server.

SCR-2189

Summary: New configuration option for the post-auth allow request of the Weakforced connector

Effective: 8.55.481 and later

The Weakforced connector now sends the session attributes configured through com.openexchange.weakforced.attributes with the report request.

  • com.openexchange.weakforced.attributes.postAuthAllow Whether those session attributes are additionally passed through the post-auth allow request, whose result is ignored. Set it to false once the Weakforced policy reads them in its report function. Default true. Not reloadable, not config-cascade aware. File: weakforced.properties.

SCR-2185

Summary: New Mail and Mail Filter Authentication Properties for Shared Accounts

Effective: 8.55.481 and later

Shared accounts and plain secondary accounts used the same authentication properties with secondary infix. Hence, a deployment could not let secondary accounts log in with a master password while shared accounts log in with the acting user's own credentials, for example. Each of these properties now has a counterpart with sharedaccount infix that applies to shared accounts only, and falls back to the secondary one if not set:

  • com.openexchange.mail.sharedaccount.passwordSource
  • com.openexchange.mail.sharedaccount.masterPassword
  • com.openexchange.mail.sharedaccount.authType
  • com.openexchange.mail.sharedaccount.masterUserSeparator
  • com.openexchange.mail.sharedaccount.authorizationId.enabled
  • com.openexchange.mail.transport.sharedaccount.authType
  • com.openexchange.mail.filter.sharedaccount.passwordSource
  • com.openexchange.mail.filter.sharedaccount.masterPassword
  • com.openexchange.mail.filter.sharedaccount.credentialSource
  • com.openexchange.mail.filter.sharedaccount.preferredSaslMech
  • com.openexchange.mail.filter.sharedaccount.masterUserSeparator
  • com.openexchange.mail.filter.sharedaccount.authorizationId.enabled

None of them has a default value, and all are reloadable and config-cascade aware. An explicitly empty masterUserSeparator turns off the master login for shared accounts, even if the secondary one is set. Plain secondary accounts are unaffected and keep using the secondary properties, so no operator action is required. See also SCR-2151.

SCR-2180

Summary: New configuration option for deleting left-over shared attachment folders of drafts

Effective: 8.55.481 and later

New configuration option for deleting the left-over shared attachment folders of drafts.

  • com.openexchange.mail.compose.share.leftOverFolders.minAge Clearing a mail folder spends at most 5 seconds checking the cleared mails for references to folders that hold shared attachments. If that check does not complete, the user's draft attachment folders that no mail refers to anymore are deleted in the background, provided they are older than this many milliseconds. A younger folder might belong to a draft that is just being stored. A value less than or equal to 0 (zero) is ignored and the default is used. Default 3600000. Reloadable, config-cascade aware. No dedicated properties file.

SCR-2179

Summary: Provisioning HTTP gateway exposes DataExportService by default; new properties com.openexchange.gdpr.dataexport.administrative.maxTimeToLive and com.openexchange.mail.admin.masterUserSeparator

Effective: 8.55.481 and later

The default of provisioningGateway.services in the core-mw chart now includes com.openexchange.grpc.provisioning.DataExportService, so the provisioning HTTP gateway offers the data export routes:

  • GET /prov/v1/contexts/{context_id}/data-export-tasks
  • GET /prov/v1/contexts/{context_id}/users/{user_id}/data-export-task
  • POST /prov/v1/contexts/{context_id}/data-export-tasks:cancel
  • POST /prov/v1/contexts/{context_id}/users/{user_id}/data-export-task:cancel
  • POST, GET and DELETE /prov/v1/contexts/{context_id}/users/{user_id}/administrative-data-export-task to start, show and delete an export an administrator starts on behalf of a user, and POST …/administrative-data-export-task:cancel to cancel it
  • GET …/administrative-data-export-task/packages/{number} to download a result package as a stream, GET …/packages/{number}:read to read it in chunks

They take the credentials of the context administrator, the master administrator only where MASTER_ACCOUNT_OVERRIDE is enabled. A deployment that sets provisioningGateway.services itself keeps its list; to not offer the routes, leave the service out.

The new lean property com.openexchange.gdpr.dataexport.administrative.maxTimeToLive sets how long the results of an administrative export are kept. It is empty by default, which keeps them as long as the user's own exports (com.openexchange.gdpr.dataexport.maxTimeToLive), and is neither reloadable nor config-cascade aware.

POST /prov/v1/contexts/{context_id}/users/{user_id}/administrative-data-export-task accepts an optional mailCredential for the user's mailbox: password, or accessToken with optional accessTokenExpires, refreshToken, oidcBackendPath and oauthMechanism (XOAUTH2 default, or OAUTHBEARER); plus masterUser if it is a master user's.

The new lean property com.openexchange.mail.admin.masterUserSeparator sets the separator of the master login MW composes for a master user's credential, e.g. * for Dovecot's auth_master_user_separator. It is empty by default, so no master user can be used, and is reloadable and config-cascade aware.

SCR-2163

Summary: New configuration options for the synchronization of POP3 accounts

Effective: 8.55.481 and later

New configuration options to limit the synchronization of external POP3 accounts.

  • com.openexchange.pop3.maxConcurrentSyncs The max. number of POP3 synchronizations running in parallel on a node. Formerly fixed to 10. Default 10. Not reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.pop3.maxConcurrentSyncsPerUser The max. number of POP3 synchronizations running in parallel for one user, so a user with many slow POP3 accounts cannot occupy all slots of com.openexchange.pop3.maxConcurrentSyncs. Further accounts of that user stay due and are synchronized afterwards. A value less than or equal to 0 (zero) means no per-user limit. Default 1. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.pop3.syncTimeBudget The time budget of a single POP3 synchronization in milliseconds. Once exceeded, no further messages are retrieved and the rest stays on the server for the next synchronization; at least one message is retrieved per synchronization. A value less than or equal to 0 (zero) means no budget. Default 300000. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2161

Summary: New properties com.openexchange.file.storage.opencloud|nextcloud.identityProvider.* for the storage account of the identity the user logged in with

Effective: 8.55.481 and later

In a deployment whose identity provider grants access to the groupware and to OpenCloud or Nextcloud alike, e.g. keycloak in front of OX App Suite and OpenCloud, a user has an account in the storage under the reserved identifier idp without creating one: the server exchanges the token of the session for one meant for the storage (RFC 8693 token exchange). OpenCloud is accessed with that token, so no credentials of OpenCloud are stored anywhere. Nextcloud is accessed with an app password the server obtains once with that token, as Nextcloud logs the user in anew for every request that carries a token and lists each of these logins among the user's devices and sessions. The app password is kept per user and instance, encrypted with the secret of the user, and replaced by a new one if the user removes it. The account is listed with the storage's product name next to the accounts the user created, cannot be created, changed or deleted, and only exists for a session that was logged in through the identity provider. It can be made the default file storage with com.openexchange.file.storage.default=opencloud://idp.

New lean configuration properties, reloadable and config-cascade aware:

  • identityProvider.url, with the prefix com.openexchange.file.storage.opencloud. and com.openexchange.file.storage.nextcloud., without default: the base URL of the storage instance; set, the account exists
  • identityProvider.audience, with both prefixes, without default: the client the exchanged token is meant for, as registered at the identity provider
  • identityProvider.scope, with both prefixes, without default: the scope the exchanged token is requested with; with keycloak openid together with the client scope that carries the audience mapper for the storage, e.g. openid opencloud-audience, that scope bound to the groupware's client as an optional scope
  • com.openexchange.file.storage.nextcloud.identityProvider.deviceName: the name the app password shows up with among the user's devices and sessions in Nextcloud; sent as user agent, so ASCII only; it defaults to OX App Suite (required, do not delete)

Note for operators: the identity provider has to allow the exchange. For keycloak that is standard token exchange on the groupware's client, and one client scope per storage with an audience mapper for the storage's client and the mappers for the claims the storage maps its users by, username, email and full name, added to userinfo, bound to the groupware's client as an optional scope and named in identityProvider.scope together with openid, as the storages read the claims of the user from the userinfo endpoint, which keycloak only serves to a token with that scope. An exchange without the right scope fails with "Requested audience not available", which the log shows. Nextcloud's OpenID Connect app has to be configured to check bearer tokens, and Nextcloud has to allow app passwords (auth_can_create_app_token, enabled by default). For Nextcloud, com.openexchange.secret.secretSource must not depend on the password, which a session logged in through the identity provider lacks; without a usable secret, the token itself is used and a warning is logged once per session. A failed exchange is logged as a warning, and the user has no account in the storage for the next five minutes. An app token or app password of the storage configured by an operator for a user is not supported.

See the feature documentation for further details.

SCR-2160

Summary: New property com.openexchange.gdpr.dataexport.provider.infostore.includeExternalDefaultFileStorage

Effective: 8.55.481 and later

The GDPR data export of the Drive module always covers the built-in infostore. Where another storage is the user's default file storage (see com.openexchange.file.storage.default), such as OpenCloud or Nextcloud, its personal, public, shared and trash folders are exported in addition, below a directory named after the account. The files are read from that storage over the network at export time, and what the archive holds depends on what the storage serves: deleted files of OpenCloud, for example, are exported with their structure only, which the report of the export notes. A storage that cannot be accessed is retried as long as the export may retry, then the infostore is exported alone and the report says so.

The new lean configuration property com.openexchange.gdpr.dataexport.provider.infostore.includeExternalDefaultFileStorage lets an operator leave the external default storage out, in which case the infostore is exported alone and the report says so. It defaults to true, is reloadable and config-cascade aware.

SCR-2157

Summary: New property com.openexchange.file.storage.default selects the default file storage of a user

Effective: 8.55.481 and later

In order to let new files of a user go to an external file storage while the built-in infostore stays available, the new lean configuration property com.openexchange.file.storage.default selects the user's default file storage among the storages the user holds. Drive Mail stores its attachments there, mail attachments are saved there, its folders are the default folders for documents, pictures, music, videos and templates, and the folders actions home, public and sharedWithMe answer its folders. The value is a qualified account identifier of the form <service-id>://<account-id>, e.g. opencloud://10. It defaults to com.openexchange.infostore://infostore, is reloadable and config-cascade aware.

Only the infostore, OpenCloud and Nextcloud can be the default. Any other value, one that cannot be parsed included, is logged as a warning and the infostore serves instead, as it does for a user without an account in the configured storage. The resolver is provided by the new bundle com.openexchange.file.storage.primary in the open-xchange-core package.

Note for operators: the folder tree is the same for every user, the system folders 9, 10 and 15 serve the infostore, and no data is migrated when the default changes. The OX Drive synchronization clients only synchronize the services listed in com.openexchange.drive.enabledServices. Folder and file identifiers of OpenCloud and Nextcloud accounts are stable across renames and moves since this change; identifiers issued before keep resolving as long as the path of the item is unchanged.

See the feature documentation for further details.

SCR-2153

Summary: New configuration options for the IMAP store cache

Effective: 8.55.481 and later

The IMAP store cache keeps a connection longer for accounts that send requests in short intervals, within a per-node budget.

  • com.openexchange.imap.storecache.maxIdleSeconds Max. time in seconds an idle IMAP connection is kept for an account that borrows again in short intervals. The actual time is 1.5 times the account's typical gap between returning a connection and borrowing the next one, but never less than com.openexchange.mail.mailAccessCacheIdleSeconds. If it would exceed this value, com.openexchange.mail.mailAccessCacheIdleSeconds applies. A value not greater than com.openexchange.mail.mailAccessCacheIdleSeconds disables the adaptation. Default 30. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.imap.storecache.maxExtendedIdleStores Number of idle IMAP connections per node up to which a connection is kept longer than com.openexchange.mail.mailAccessCacheIdleSeconds. Once reached, every returned connection is kept for com.openexchange.mail.mailAccessCacheIdleSeconds only. 0 (zero) derives the value from the max. heap size: one connection per 3 MiB, e.g. 682 for a 2 GiB heap. A negative value means unlimited. Default 0. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2151

Summary: New Properties to Log In to Secondary and Shared Accounts via SASL PLAIN With the Acting User's Password

Effective: 8.55.481 and later

In order to access secondary and shared accounts with the acting user's own login and session password, App Suite can authenticate via SASL PLAIN as the acting user and pass the account's login as authorization identity. The following properties are introduced:

  • com.openexchange.mail.secondary.authorizationId.enabled for IMAP and SMTP
  • com.openexchange.mail.filter.secondary.authorizationId.enabled for Sieve

They default to false, are reloadable and config-cascade aware. They only take effect with the session password (passwordSource=session) and only for IMAP, SMTP and Sieve. If a master user separator (SCR-2131) is configured as well, they take precedence. The mail server has to accept such logins and verify that the acting user may access the account, e.g. through a master passdb. For mail sent through such an account, the data retention identifier and the audit log name the acting user's login.

See the feature documentation and the property documentation for further details.

SCR-2143

Summary: New property com.openexchange.deputy.sendAsEnabled and capability deputy_send_as

Effective: 8.55.481 and later

The new lean configuration property com.openexchange.deputy.sendAsEnabled controls whether a granting user may let a deputy send E-Mails as the granting user, i.e. with the granting user as From and without a Sender header, so recipients cannot tell that the deputy sent the E-Mail. It defaults to false, is reloadable and config-cascade aware, and is evaluated for the granting user. Clients learn about it through the new capability deputy_send_as.

  • While the property is false, granting "send as" is rejected with DEPUTY-0016; passing back an already stored value unchanged is still accepted.
  • Disabling it takes effect on existing grants immediately: a grant of "send as" then acts as "send on behalf of", and notification mails sent to the deputy meanwhile name that form. The stored grant is kept and takes effect again once the property is enabled.
  • Administrative provisioning (SOAP, RMI, gRPC, SCIM) is not restricted by the property. Grants of "send as" provisioned while it is disabled take effect as soon as it is enabled, also when it is enabled for the first time.

"Send as" covers E-Mails only: notification and iTIP mails a deputy triggers in the granting user's calendar are always sent on behalf of the granting user. Technical traces of the deputy outside the mail headers remain possible, see the known limitations.

Note for operators: the SMTP server has to accept the granting user's address as From for the deputy's login without a Sender header. During a rolling upgrade, enable the property and provision "send as" only once all nodes run this version: older nodes ignore the stored flag and delete a grant of "send as" without any module as soon as they read it, e.g. when the deputy opens App Suite on such a node.

See the feature documentation for further details.

SCR-2139

Summary: New properties to send SMS via sipgate with a personal access token and a chosen SMS extension

Effective: 8.55.481 and later

In order to authenticate against the sipgate REST API with a personal access token, which sipgate intends as the long-term replacement for account password logins, the following properties are introduced for the sipgate SMS provider:

  • com.openexchange.sms.sipgate.tokenId and com.openexchange.sms.sipgate.token for the personal access token, which needs the scope sessions:sms:write
  • com.openexchange.sms.sipgate.smsId for the SMS extension that text messages are sent from; it defaults to s0, the extension used so far

All are reloadable and config-cascade aware. com.openexchange.sms.sipgate.username and com.openexchange.sms.sipgate.password are deprecated: they are only used while no personal access token is configured, and a warning is logged once per node when they are. Existing configurations keep working without operator action.

See the property documentation for further details.

SCR-2137

Summary: New and changed configuration options for nodes that come and go, e.g. on Kubernetes

Effective: 8.55.481 and later

These settings help nodes that come and go, e.g. on Kubernetes: one lets all nodes share the upload directory, so that a file outlives the node that received it, one lets another node take over background update tasks a dead node left unfinished, one keeps slow clients connected while a node drains its requests, and the core-mw Helm chart now limits how many pods a node drain stops at once.

  • com.openexchange.filemanagement.sharedUploadDirectory Whether the upload directory set by com.openexchange.server.UPLOAD_DIRECTORY is shared by all nodes, e.g. a mounted NFS volume. If enabled, files that other nodes may access later on, like attachments uploaded before a mail is sent or large results of jobs that ran in the background, are kept there together with their properties: any node finds them, a node that shuts down leaves them in place, and they are deleted once no node accessed them within their time-to-live. On start-up, a node then only deletes remnants older than one day. Set it the same on all nodes. Default false. Not reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.groupware.update.background.idleMillis The idle time in milliseconds after which the lock of a schema's background update tasks counts as timed out, so that another node runs the remaining tasks. With the former default, a lock left behind by a node that died while running background update tasks was never released. Must exceed com.openexchange.groupware.update.refreshIntervalMillis. Default changed from 0 to 60000. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.http.jetty.shutdownIdleTimeoutMillis The idle timeout in milliseconds that open connections get once a node shuts down and drains its requests (see com.openexchange.connector.awaitShutDownSeconds). A connection without I/O for that long is closed, an idle keep-alive connection as well as a slow upload that pauses. Formerly fixed at 1 second, which dropped such uploads. A value less than or equal to 0 (zero) keeps the regular idle timeout of com.openexchange.http.jetty.readTimeoutMillis. Default 5000. Not reloadable, not config-cascade aware. No dedicated properties file.

  • pdb Value of the core-mw Helm chart. The chart now creates a PodDisruptionBudget per type, so that a node drain or another voluntary disruption stops one pod of a type at a time; that never blocks a drain, not even with a single replica. Defaults changed: pdb.create from false to true, pdb.maxUnavailable from empty to 1. pdb.minAvailable takes precedence if set; a value equal to the number of replicas blocks drains. Set pdb.create to false to go without.

  • keda New values of the core-mw Helm chart. With keda.enabled set to true, the chart creates a KEDA ScaledObject per type that scales on the average number of HTTP API requests in progress per pod, derived from appsuite_httpapi_requests_seconds_sum, optionally also on CPU utilization. Required: keda.prometheus.serverAddress and keda.prometheus.threshold. keda.minReplicaCount must be at least 1; KEDA and hpa.create are mutually exclusive. Default keda.enabled is false.

Readiness: a failed health check is evaluated again after 2 seconds instead of reusing the result for 10 seconds, so a pod is ready again right after a short outage of a backing service such as a Redis failover. A successful result is still reused for 10 seconds.

Session removals: a logout or an administrator's removal of sessions while the main Redis is unreachable is applied to Redis within a few seconds after it is reachable again. Formerly such sessions became valid again once Redis was back. A node that shuts down meanwhile logs how many removals it could not apply.

  • com.openexchange.push.permanent.maxStartsPerSecond New. The number of permanent push listeners holding resources (IMAP IDLE, mail notify) a node starts per second at most, and stops per second without being asked for them by another node. When nodes come or go, users move at this rate per starting node; a user keeps its listener on the former node until the new one is about to start it, so it goes without push for a few seconds only. Moving takes the number of listeners a node takes over, one per user and push manager, divided by this rate. Default 10. Reloadable, not config-cascade aware. File mail-push.properties.

  • com.openexchange.push.rescheduleOnRegistration Removed, together with the master node that started all permanent push listeners. Each registered user now belongs to one node, determined by rendezvous hashing over the live nodes; that node starts the user's permanent listeners, also for registrations made on other nodes.

  • POD_NAME_STABLE New environment variable the core-mw Helm chart sets for StatefulSets only. A pod of a StatefulSet then keeps its identifier across restarts and gets its users back. Other pods use a random identifier per start. Nothing to configure.

Permanent push listeners: IMAP IDLE and mail notify listeners are now spread over all nodes instead of running on one master node. Nodes announce themselves and hold a lease per user in Redis; Lua scripting must be enabled there (the default). A node that cannot renew its leases for 60 seconds stops its permanent listeners, so an outage of the main Redis shorter than 30 seconds stops nothing. The users of a node killed without shutting down start on the others once its leases expired, after about 90 seconds; the node holding a user's lease takes over the IMAP IDLE lock a stopped permanent listener left behind, but never the lock of a listener for a session. While a node of a former version still runs its master, permanent listeners keep starting where they are registered.

Mail notify without multicast: a node receiving a notification for a mailbox it holds no listener for forwards it via Redis Pub/Sub to the node holding the permanent listener. The metric appsuite.push.mailnotify.forward.dropped counts notifications dropped as too many were waiting. Dovecot push registrations are no longer renewed when the master changes, as there is none.

  • javaOpts.aotCache New value of the core-mw Helm chart. The image now ships a JDK AOT cache, trained on its bundles when the image is built, and starts the JVM with it (JAVA_OPTS_AOT): the middleware starts about a fifth faster. The cache fits only G1 with Compact Object Headers and a heap below 32 GB; with javaOpts.zgc or without javaOpts.compactObjectHeaders the chart turns it off. Default true. Set it to false to start without the cache.

  • probe Values of the core-mw Helm chart. The startup probe checks every 2 seconds after 10 seconds, so that a started pod becomes ready within a few seconds instead of up to 15. Defaults changed: probe.startup.initialDelaySeconds from 30 to 10, probe.startup.periodSeconds from 10 to 2, probe.startup.failureThreshold from 30 to 160, which keeps the start-up budget at 330 seconds. probe.readiness.initialDelaySeconds changed from 30 to 5, as the readiness probe only runs once the startup probe succeeded.

  • startupCPUBoost New values of the core-mw Helm chart. The main container of a starting pod gets startupCPUBoost.cpu and is resized in place to resources once the pod is ready, without a restart: with a CPU limit of 500m, a pod was ready after 53 to 63 seconds instead of 155 to 162. By default (startupCPUBoost.enabled auto) only a CPU limit above the request is raised, and only the limit, so the pod is scheduled as without the boost; this needs Kubernetes 1.33 or later and the chart's Role, which then allows patching pods/resize. A pod without a CPU limit or with a limit equal to its request is not boosted then. With true those are boosted too: the request is raised along with the limit, so the pod keeps its QoS class and is scheduled with the boosted request. false turns the boost off. After startupCPUBoost.maxSeconds the CPU is lowered even if the pod has not become ready. Defaults: startupCPUBoost.enabled auto, startupCPUBoost.cpu 2, startupCPUBoost.maxSeconds 600.

  • initWait.middlewareTimeout Removed from the core-mw Helm chart, together with the init container's INIT_MW_WAIT_TIMEOUT. With enableInitialization, the init container no longer starts the middleware for the initial bootstrap; it only creates the ConfigDB, and the main container registers server, file stores and databases and creates the demo contexts once the middleware has started there. A fresh stack thus starts the middleware once instead of twice. The pod becomes ready when the bootstrap is done.

SCR-2131

Summary: New Properties to Log In to Secondary and Shared Accounts With the Acting User's Credentials

Effective: 8.55.481 and later

In order to access secondary and shared accounts with the acting user's OAuth access token on mail servers that require the authenticated user name to match the token, such as Dovecot 2.4 and Dovecot Pro 3.1, App Suite can log in as <account login><separator><acting user login>. The following properties are introduced:

  • com.openexchange.mail.secondary.masterUserSeparator for IMAP and SMTP
  • com.openexchange.mail.filter.secondary.masterUserSeparator for Sieve

They are empty by default, which keeps the current behavior, and are reloadable and config-cascade aware. The login is only composed if the acting user's own credentials are passed, i.e. an OAuth access token or the session password. The mail server is then responsible for verifying that the acting user may access the account, e.g. through a master passdb. For mail sent through such an account, the data retention identifier is the composed login.

See the feature documentation for further details.

SCR-2130

Summary: New configuration options for Argon2 key derivations

Effective: 8.55.481 and later

Argon2 key derivations, used for the session obfuscation key and other server-side encryption, are now bounded per node, and the session obfuscation key reuses one random salt per node for up to a day, so creating or loading sessions no longer derives a key per session.

  • com.openexchange.crypto.argon.maxConcurrentDerivations Defines how many Argon2 key derivations run at once on a node; others wait up to 30 seconds for a free slot and then fail with CRP-0009. Each derivation holds com.openexchange.crypto.argon.memory of heap while it runs. A value less than or equal to 0 (zero) derives the number from the maximum heap, between 2 and 16. Default 0. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.crypto.argon.keyCacheIdleMinutes Defines how many minutes a derived key stays cached on a node without being used. Each value encrypted with its own salt, such as the password of an external mail account, needs its own key, so an expired key costs another derivation the next time that value is read. Values less than 1 fall back to the default. Default 60 (previously fixed at 10 minutes). Reloadable, not config-cascade aware. No dedicated properties file.

8.35 and 8.47 to 8.53 get only the bound on concurrent derivations: callers wait for a free slot without a time limit instead of failing with CRP-0009, and the session obfuscation key still uses a random salt per session.

SCR-2127

Summary: New configuration option for revoking access tokens after a refused mail password

Effective: 8.55.481 and later

Access tokens whose kept mail password is refused are revoked after a wait where no live session can tell a lockout from a password change.

  • com.openexchange.accesstoken.revokeOnRefusedPasswordWithoutSessionDelay How long the primary mail server has to keep refusing the password an access token keeps before tokens are revoked, where no live session of the user logged in with a password. It should outlast the lockouts the user directory imposes after failed logins. A time span such as 30m or 2h; values below five minutes are raised to five, values above one day lowered to one day. Where a live session shows that the password changed, tokens are revoked after five minutes regardless. Default 30m. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2103

Summary: New option to revoke tokens without an ID token at the OpenID Connect provider

Effective: 8.55.481 and later

An OpenID Connect back-end can revoke tokens that came without an ID token.

  • com.openexchange.oidc.opRevocationEndpoint The OpenID Connect provider's token revocation end-point (RFC 7009). Tokens without an ID token, e.g. ones the mail credential vault obtained through a token exchange, cannot be ended with an end-session request at com.openexchange.oidc.opLogoutEndpoint. Where this is set, they are revoked here: the refresh token if there is one, else the access token. May be set per back-end, e.g. com.openexchange.oidc.background.opRevocationEndpoint. For Keycloak: https://<host>/realms/<realm>/protocol/openid-connect/revoke. Default empty: such tokens expire on their own. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2099

Summary: New option to ask for a refresh token in the token exchange of the mail credential vault

Effective: 8.55.481 and later

A token exchange of the mail credential vault can ask for a refresh token.

  • com.openexchange.mail.credential.oauth.tokenExchange.requestedTokenType The token type to ask for when exchanging tokens: access_token, the default, or refresh_token; the full URN of either type is taken as well, anything else is logged and an access token asked for. With refresh_token, an identity provider that allows it hands out a refresh token as well, so the exchanged credential is refreshed and kept alive instead of expiring with its access token. Keycloak does so where the client allows refresh tokens in its standard token exchange. May be set per feature by appending the feature identifier, e.g. com.openexchange.mail.credential.oauth.tokenExchange.snoozed-mail.requestedTokenType. Default access_token. Reloadable, config-cascade aware. No dedicated properties file.

SCR-2093

Summary: New option for changing the session encryption key without losing sessions

Effective: 8.55.481 and later

The session encryption key can now be changed without losing sessions or kept mail credentials.

  • com.openexchange.sessiond.previousEncryptionKey The former value of com.openexchange.sessiond.encryptionKey after a change. Data obfuscated with it stays readable: sessions stored before the change, and the credentials of the mail credential vault, which the vault seals again with the new key. Only the current key obfuscates. In a cluster updated node by node, first set the new key here on every node, then swap both values. Keep the former key as long as the longest session lives and until the vault reports for every schema that it is no longer needed. Other data obfuscated with the key, e.g. passwords of secondary mail accounts, is not sealed again and becomes unreadable once the former key is removed. Default empty. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.sessiond.encryptionKey Now reloadable.

  • com.openexchange.mail.credential.previousEncryptionKey Falls back to com.openexchange.sessiond.previousEncryptionKey when empty, so one setting covers sessions and kept credentials.

SCR-2092

Summary: New configuration option to read the text of PDF files through MCP

Effective: 8.55.481 and later

This option controls whether the MCP server /mcp reads the text of PDF files.

  • com.openexchange.mcp.documents.localPdf Whether file_get, mail_attachment_get and the resource reads of files and attachments read the text of a PDF file on the node. It does not depend on the document converter; office documents go through the converter regardless. A PDF above 5 MiB, one that takes longer than 20 seconds, a protected one, or one whose streams decode to more than 32 MiB is served as without this option. Default false. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2086

Summary: New configuration options for the token keep-alive and key rotation of the mail credential vault

Effective: 8.55.481 and later

The mail credential vault gets two options: one keeps the OAuth tokens it stores alive, the other carries the former session encryption key through a change of that key.

  • com.openexchange.mail.credential.oauth.keepAliveInterval How long OAuth tokens kept by the vault go without a refresh before an hourly job refreshes them, so that the identity provider does not end their session for being idle; Keycloak ends offline sessions after 30 days by default. A time span such as 3D; 0 switches the keep-alive off, a value below one hour is raised to one hour, and an invalid value is logged and the default used. Default 3D. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mail.credential.previousEncryptionKey The former value of com.openexchange.sessiond.encryptionKey after that key was changed. Credentials sealed with it stay readable and are sealed again with the new key, when used and by an hourly job, which logs per schema when the former key is no longer needed. Without it, kept credentials are lost with a change of the key. Default empty. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2085

Summary: New Configuration Property to Use Pushed Authorization Requests in the OpenID Connect Authorization Code Flow

Effective: 8.55.481 and later

The new lean configuration property com.openexchange.oidc.opPushedAuthorizationRequestEndpoint enables Pushed Authorization Requests (PAR, RFC 9126) for OpenID Connect logins. It defaults to an empty value, is reloadable and not config-cascade aware.

If set, the parameters of each authentication request, including state, nonce and the PKCE code challenge, are pushed to the OpenID Provider over the back channel, and the browser is only redirected with the returned request_uri. The OpenID Provider has to support PAR and can then require it; there is no fallback if the push fails. No behavior change for existing deployments.

See the property documentation and the feature documentation for further details.

SCR-2078

Summary: New configuration options for the MCP activity log

Effective: 8.55.481 and later

These options bound what the MCP server /mcp records about the calls made through access tokens.

  • com.openexchange.mcp.activity.maxEntriesPerToken How many calls of one access token are recorded at most; an hourly clean-up drops the oldest beyond. A value less than or equal to 0 (zero) records nothing. Default 1000. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.activity.retentionDays How many days recorded calls are kept; the hourly clean-up drops older ones. A value less than or equal to 0 (zero) keeps them as long as com.openexchange.mcp.activity.maxEntriesPerToken allows. Default 30. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2072

Summary: New configuration options for the built-in OAuth authorization server of the MCP server

Effective: 8.55.481 and later

These options govern the built-in OAuth authorization server of the MCP server /mcp.

  • com.openexchange.mcp.oauth.enabled Whether the middleware acts as authorization server for /mcp. The endpoints without a user (metadata, registration, token) follow the server-level value and answer 404 while it is off; the sign-in follows the user's value, so a context or user can be excluded, and a user excluded later cannot refresh any more. Default false. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.oauth.allowedRedirectHosts Comma-separated hosts a client may register redirect URIs for, for example claude.ai, chatgpt.com, loopback; loopback stands for 127.0.0.1, [::1] and localhost. Empty accepts every host; redirect URIs must use https, or http on a loopback host, either way. Registration checks the server-level value, the sign-in the user's as well. Default empty. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.oauth.registrationsPerHour How many new clients one address may register per hour; an IPv6 address counts by its /64 prefix, and a public client registering the same metadata again gets the same registration without counting. Authorization requests are limited to 30 times this value per address. A value less than or equal to 0 (zero) disables both limits. Default 10. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.oauth.accessTokenMinutes How many minutes an access token issued by the built-in authorization server is valid; the client then refreshes it. A grant ends after com.openexchange.accesstoken.maxLifetimeDays, or 365 days if that is 0. Default 60. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.oauth.clientMetadataDocuments Whether a client may name itself by the https URL of a client ID metadata document instead of registering. The middleware then fetches that document directly, not through a proxy, and only from public addresses; without direct outbound HTTPS to the clients' hosts, set it to false. Default true. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2069

Summary: New properties for the OX Guard client's token storage under external authentication

Effective: 8.55.481 and later

Under external authentication the OX Guard client keeps the per-session Guard authentication tokens in Cassandra, since the session is transient on the middleware: the table guard_auth_tokens holds one row per token, keyed by the external session and the crypto type, and each row expires with the lifetime the user chose for the token. The table is created on first use. Classic sessions keep their tokens on the groupware session.

  • com.openexchange.guard.cassandraTokenKeyspace The Cassandra keyspace holding the tokens; has to be a valid unquoted CQL identifier. Default guard.

  • com.openexchange.guard.cassandraTokenAutoCreateKeyspace Whether the keyspace is created when missing; meant for test and development setups. Default false.

The Guard client's own credentials travel in the header X-OX-GUARD-BASIC-AUTH instead of Authorization, which carries the user's bearer token; this requires a Guard server that accepts it.

SCR-2064

Summary: New properties to enable external authentication and the OIDC handoff

Effective: 8.55.481 and later

The following lean properties control external authentication, where an external service authenticates the user, owns the session and hands the middleware a JWT per request:

  • com.openexchange.external.authentication.enabled Enables external authentication. Default false. Not reloadable, not config-cascade aware.

  • com.openexchange.external.authentication.oidc.handoffRedirectURL Base URL of the external service's OIDC handoff resource; the middleware appends the flow token as last path segment once the OpenID Connect flow has obtained the tokens. Only used while external authentication is enabled. Default empty. Reloadable, not config-cascade aware.

With the defaults nothing changes for existing deployments.

SCR-2060

Summary: New Property com.openexchange.contact.crosscontext.enabled

Effective: 8.55.481 and later

The new property com.openexchange.contact.crosscontext.enabled enables the cross-context contacts provider, which surfaces address books shared from other contexts. Users it is available to get the capability contact_crosscontext. It is the instance of the generic com.openexchange.contact.[providerId].enabled for the provider crosscontext. It defaults to true, and is reloadable and config-cascade aware.

The generic com.openexchange.contact.[providerId].enabled is now evaluated per user and context, as documented; before, it was only read at server scope. Values set at context or user level for other contacts providers therefore take effect now.

See the property documentation and the feature documentation for further details.

SCR-2055

Summary: New configuration options for MCP tools that change data

Effective: 8.55.481 and later

These options govern the tools of the MCP server /mcp that change data.

  • com.openexchange.mcp.write.enabled Whether tools that change data are listed by tools/list and callable at /mcp. A token still needs the module's write scope, such as write_calendar. The option governs /mcp only: a token with a write scope writes through the HTTP API as before. Default false. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.mail.sendDelay How many seconds mail_send holds a confirmed mail in scheduled mail before it goes out, so that it can still be stopped with mail_scheduled_cancel or in App Suite. Values above 600 count as 600; 0 sends at once, as before. Where the user cannot schedule mails, the mail goes out at once and the result says so. Default 60. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.write.confirmSecret The secret the confirmation tokens of MCP write calls are signed with. A tool that changes data answers preview: true with a confirmToken, valid for five minutes, and writes only when called again with that token and exactly the previewed arguments. Set the same value of at least 32 characters on every node; empty or shorter leaves writing unavailable. Default empty. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.rateLimit.writeCalls How many calls of tools that change data a user may make per window of com.openexchange.mcp.rateLimit.windowSeconds, counted across all nodes and on top of com.openexchange.mcp.rateLimit.calls. A call with preview: true counts as a read. A value less than or equal to 0 (zero) disables this limit. Default 20. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.write.externalAttendees Whether the tools may reach addresses outside the installation, in the calendar and by mail alike: add them as attendees or send them text, send them mail with mail_send, or give a vacation notice that replies to them a new text. While it is false, such a call is refused before anything is saved; answers and changes without text to external attendees already on an appointment still go out. To allow external attendees but no mail to external recipients, also set com.openexchange.mcp.tools.disabled=mail_send. Default false. Reloadable, config-cascade aware. No dedicated properties file.

SCR-2051

Summary: New Property for Refreshing the LDAP Contacts Provider Cache in the Background

Effective: 8.55.481 and later

In order to spare requests from waiting for the cache of an LDAP contacts provider to be loaded, a cache in use is now refreshed in the background before it expires. The first access once the cache has reached a certain age triggers loading its data anew, while the current data continues to be served until the refreshed data is available. An unused cache still expires after com.openexchange.contacts.ldap.cache.expire and is loaded again upon the next access, as before.

The new lean configuration property com.openexchange.contacts.ldap.cache.refresh defines that age. It is empty by default, which means 90% of com.openexchange.contacts.ldap.cache.expire (108 minutes with its default of 2h), and is reloadable, but not config-cascade aware. Setting it to 0 disables refreshing in the background and restores the previous behavior.

See the property documentation for further details.

SCR-2049

Summary: New configuration options for user feedback pseudonyms

Effective: 8.55.481 and later

A new option keys the pseudonyms of users in exported feedback.

  • com.openexchange.userfeedback.pseudonym.secret The secret for the HMAC-SHA256 pseudonyms of users in exported NPS and star rating feedback. Use the same value on all nodes. If empty, a random secret is used per node and start, so pseudonyms differ between nodes and restarts. Default empty. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2036

Summary: New Configuration for Preconfigured iCal Subscriptions

Effective: 8.55.481 and later

Administrators can now provide read-only calendars from iCal feeds, e.g. public holidays or a canteen menu, that are defined once and provisioned automatically to all users they are enabled for, across contexts. Each user gets such a calendar in the public calendars section, with own color, subscription, schedule transparency, CalDAV synchronization and alarms. The following configuration is new:

  • The file calendar-provider-preconfiguredical.yml defines the available subscriptions, one section per subscription with name, uri, optional credentials, refreshInterval and sharedCache, as well as the per-user settings color, scheduleTransp, shownInTree and usedForSync, each either as initial value or protected from changes. A template is available as calendar-provider-preconfiguredical-template.yml.
  • com.openexchange.calendar.preconfiguredical.subscriptions enables subscriptions for users as comma-separated list of their keys. Empty by default, config-cascade aware.
  • com.openexchange.calendar.preconfiguredical.enabled enables the calendar provider preconfiguredical with capability calendar_preconfiguredical. Defaults to true, config-cascade aware.
  • com.openexchange.calendar.preconfiguredical.usedForSync controls whether these calendars can be synchronized via CalDAV at all. Defaults to true, config-cascade aware.
  • com.openexchange.calendar.preconfiguredical.cleanup.gracePeriod defines how long a daily clean-up job waits before removing the calendars and cached data of subscriptions that were removed from the file. Defaults to 7D.
  • The feeds are retrieved with an own HTTP client preconfiguredical, configurable through com.openexchange.httpclient.preconfiguredical.*. Other than for personal subscriptions, internal hosts are allowed, while redirects are only followed to the same host.

All properties are reloadable. No operator action is required; without subscriptions defined and enabled, nothing changes.

See the documentation, as well as the property documentation for further details.

SCR-2034

Summary: New configuration options for keeping the mail login inside the context

Effective: 8.55.481 and later

Options that keep the mail login and mail server of users and shared accounts inside their context.

  • com.openexchange.mail.login.restrictToContext Whether the mail login of users and shared accounts is kept inside their context. If true, context administrators are bound to the login mappings of the context and to com.openexchange.admin.user.mailServersForContextAdmin, and administrative mail access refuses a stored login that a mail login resolver maps to another user. Read for the context only, never for a user. Default false. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.admin.user.mailServersForContextAdmin Comma-separated mail servers that context administrators may set as imapServer while com.openexchange.mail.login.restrictToContext is true. A plain host name stands for imap://<host>:143. Default empty, meaning none. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-2027

Summary: New configuration option for the audience of JWTs accepted by the MCP server

Effective: 8.55.481 and later

The MCP server endpoint /mcp can require that a JWT was issued for it.

  • com.openexchange.mcp.audience Comma-separated audiences of which a JWT has to name at least one in its aud claim to be accepted by /mcp; any other JWT is answered with 401 and invalid_token. Set it where the authorization server also issues tokens for other clients, such as the mobile app, since com.openexchange.oauth.provider.jwt.audience applies to every resource server of the installation alike. Empty accepts every JWT the OAuth provider accepts; the endpoint then logs a warning at start-up if com.openexchange.oauth.provider.jwt.jwksUri is set or the OAuth provider runs in mode token_introspection. Personal access tokens are not affected. Default empty. Reloadable, not config-cascade aware. No dedicated properties file.

Each audience is compared as a whole, so one with spaces such as OX App Suite, the default audience of the external authentication service, is matched, and a single word of it is not. The same applies to com.openexchange.mobile.auth.idp.audience of the Mobile API.

SCR-2024

Summary: The provisioning HTTP gateway can expose MailFilterAdminService

Effective: 8.55.481 and later

com.openexchange.grpc.provisioning.MailFilterAdminService can be added to provisioningGateway.services of the core-mw chart. It is not in the default list, because it reads and changes the mail filter rules of any user of a context. Over gRPC and RMI the service is available to administrators regardless of the gateway, as every provisioning service is.

SCR-2023

Summary: New configuration options for administrative mail access

Effective: 8.55.481 and later

Options for how the middleware reaches a user's mailbox and Sieve scripts without the user's password, e.g. for deputy permissions on mail and the mail filter provisioning API.

  • com.openexchange.mail.admin.strategies The comma-separated order of the strategies token, doveadm and master. IMAP and Sieve are resolved separately; per protocol the first strategy that applies wins. token applies only when a token is at hand: one passed by the provisioning call, or one kept in the credential vault for a feature named in com.openexchange.mail.admin.token.vaultFeatures. An empty value switches administrative mail access off, which also stops the Dovecot push registration without a session and the retraction of cross-context mail shares. Default token,doveadm,master. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.mail.admin.token.vaultFeatures The comma-separated features of the credential vault whose kept OAuth tokens may serve administrative mail access. Tokens kept for other features are never used this way. Default empty, which uses no kept token. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mail.admin.considerResolver Whether the login that addresses a mailbox administratively comes from the mail login resolver. It replaces the undocumented com.openexchange.deputy.provider.imap.doveadm.considerResolver, which is still honored. Default false. Reloadable, config-cascade aware. No dedicated properties file.

SCR-2009

Summary: New Configuration Property to Use PKCE in the OpenID Connect Authorization Code Flow

Effective: 8.55.481 and later

The new lean configuration property com.openexchange.oidc.pkceMethod enables Proof Key for Code Exchange (PKCE, RFC 7636) for the OpenID Connect authorization code flow. PKCE binds an authorization code to the authentication request, so that an intercepted code cannot be redeemed elsewhere. It defaults to an empty value, is reloadable and not config-cascade aware.

If set to a code challenge method, typically S256, a code challenge is sent with every authentication request, and the matching code verifier is presented when the authorization code is exchanged. The OpenID Provider can then be configured to require PKCE for the client. Method plain is discouraged, and an unsupported method leads to a failed login and a warning in the log. Set the property only once all middleware nodes are updated. No behavior change for existing deployments.

See the property documentation for further details.

SCR-2008

Summary: New Configuration Property to Bind OpenID Connect Logins to the Initiating Browser

Effective: 8.55.481 and later

The new lean configuration property com.openexchange.oidc.bindStateToBrowser binds an OpenID Connect authentication request to the browser that initiated it, which protects against login CSRF. It defaults to false, is reloadable and not config-cascade aware.

If enabled, the init request sets the short-lived cookie open-xchange-oidc-state-<state>, and the authentication callback is only accepted from a browser that presents it. The cookie is scoped to the host and path of com.openexchange.oidc.rpRedirectURIAuth, and is sent with SameSite=None; Secure for an https callback, so that the silent relogin inside an iframe still works. The init request therefore has to reach the same host as the callback. No behavior change for existing deployments.

See the property documentation for further details.

SCR-2003

Summary: New configuration options for Mobile API push notifications

Effective: 8.55.481 and later

The following options control push notifications for Mobile API apps through APNs and FCM. All are reloadable, config-cascade aware and have no dedicated properties file.

  • com.openexchange.mobile.push.notificationContent What a visible new-message push reveals to Apple or Google when a subscription asks for nothing: none (a neutral text), sender or senderAndSubject. Default none. An unknown value counts as none.

  • com.openexchange.mobile.push.maxNotificationContent The most a subscription may ask a new-message push to reveal; a higher request is lowered to it, also for existing subscriptions. Default senderAndSubject. An unknown value counts as none.

  • com.openexchange.mobile.push.maxSubscriptionsPerUser The most push subscriptions a user may hold across all Mobile API apps; a further registration is refused with 422. Registering a device again does not count. 0 means no limit. Default 20.

SCR-1978

Summary: New configuration options for live change events

Effective: 8.55.481 and later

The new push notification transport sse delivers notifications to live change streams (Server-Sent Events). The following options control it.

  • com.openexchange.pns.transport.sse.enabled Whether the transport is enabled. It can be refined per client and topic by appending .<client> and .<client>.<topic>. Default false. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.pns.transport.sse.pingInterval The interval in milliseconds in which an open stream refreshes its presence and sends a ping event to the client; a presence that is not refreshed expires after twice this interval. Default 30000. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.pns.transport.sse.maxConnectionsPerUser The maximum number of streams a user may have open across the cluster, counted per endpoint. Streams at <dispatcher prefix>events and at /mobile/v1/events do not replace each other; at /mobile/v1/events the limit applies per device (access token, or Push-Subscription-Id in mode idp). Opening one more closes the oldest stream of the same endpoint and device with reason replaced. A value less than or equal to 0 (zero) disables the limit. Default 5. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.pns.transport.sse.maxConnectionsPerNode The maximum number of streams open on one node. Further requests are rejected with HTTP status 503 and a Retry-After header, so the client can reconnect to another node. A value less than or equal to 0 (zero) disables the limit. Default 5000. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.pns.transport.sse.maxLifetime The maximum lifetime of a stream in milliseconds. Once reached, the stream ends with reason lifetime and the client reconnects. A value less than or equal to 0 (zero) is ignored and the default is used. Default 1800000 (30 minutes). Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.pns.transport.sse.tokenCheckInterval The interval in milliseconds in which the bearer token of a stream is validated again; a stream whose token was revoked or expired then ends with reason token_invalid. Keep it below 5 minutes, the time an idle OAuth session lives. A value less than or equal to 0 (zero) is ignored and the default is used. Default 120000. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.imap.liveChanges.mode How changes made outside the middleware, e.g. by another mail client, are noticed for live change streams of users whose primary account is IMAP. poll looks at the mailbox of a user with an open stream once per pollInterval, in one LIST "" "*" RETURN (STATUS (MESSAGES UIDNEXT UIDVALIDITY HIGHESTMODSEQ)) command on a pooled connection; it needs the IMAP extensions LIST-EXTENDED and LIST-STATUS, and CONDSTORE for changes that leave the message counts alone. off leaves such changes unnoticed. Changes made through the middleware are reported either way. Default poll. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.imap.liveChanges.pollInterval The interval in milliseconds in which such a mailbox is looked at. Streams are handled every 5 seconds, so shorter values take effect as 5 seconds. Default 10000. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.imap.liveChanges.maxWatches The maximum number of users a node watches this way. Streams of further users still report the changes made through the middleware. A value less than or equal to 0 (zero) disables the limit. Default 5000. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mail.liveChanges.echoWindow The time in milliseconds within which the mail server’s report of a change the middleware made itself is left out, so that a live change stream sees such a change once. It has to exceed the time the mail server needs to report a change, e.g. com.openexchange.imap.liveChanges.pollInterval. A value less than or equal to 0 (zero) switches the suppression off and reports the change twice. Default 15000. Reloadable, config-cascade aware. No dedicated properties file.

SCR-1944

Summary: New configuration options for the MCP server

Effective: 8.55.481 and later

The MCP server endpoint /mcp is configured through these properties, read when the bundle com.openexchange.mcp starts and again on a configuration reload. A reload takes the endpoint down and up again only when com.openexchange.mcp.enabled changes; every other property takes effect while the endpoint keeps answering.

  • com.openexchange.mcp.enabled Whether the MCP endpoint /mcp and its resource metadata document /.well-known/oauth-protected-resource/mcp are registered. Default false. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.allowedOrigins Comma-separated Origin header values a browser-based client may send. A request with an Origin that is not listed is answered with 403. Default empty, which refuses every request carrying an Origin header. The endpoint sends no CORS headers and answers OPTIONS with 405, so a browser client on another origin needs CORS at the ingress. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.authorizationServers Comma-separated issuer URLs advertised as authorization_servers in the RFC 9728 resource metadata. Default empty; com.openexchange.oauth.provider.allowedIssuer is advertised then, if set. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.serverName The name reported as serverInfo.name. Default open-xchange-mcp. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.instructions The natural-language guidance a client receives from server/discover. Default: a sentence describing the read-only access to mail, calendar, contacts, files, tasks, reminders and the vacation notice. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.rateLimit.calls How many tool calls and resource reads a user may make per window, counted across all nodes through the rate limiter service. Beyond that a tool call is answered as a tool result with isError and a Retry-After header, a resource read with 429 and Retry-After. A value less than or equal to 0 (zero) disables the limit. Default 60. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.rateLimit.windowSeconds The window of the tool call limit in seconds. A value less than 1 is treated as 1. Default 60. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mcp.maxConcurrentCalls How many tool calls and resource reads of one user may run at the same time on a node. A call holds its slot until its answer is written, so a client that reads slowly cannot pile up answers in memory. A further call is refused like one beyond the rate limit, with Retry-After: 1, takes no permit of the rate limit and is audited with outcome busy. Per node, since a call in flight lives on the node that runs it. A value less than or equal to 0 (zero) switches the bound off. Default 4. Reloadable, not config-cascade aware; a changed value applies to calls that start after the reload. No dedicated properties file.

SCR-1871

Summary: New Configuration Properties for the Calendar Trash Folder

Effective: 8.55.481 and later

Three new properties introduce the calendar Trash folder, i.e. the soft deletion of appointments into a reserved folder they can be restored from. The feature is off by default and is switched on deliberately, per user, context or server; all three are reloadable and config-cascade aware.

  • com.openexchange.calendar.trashFolder.enabled - enables the feature. Defaults to false, unlike com.openexchange.contact.trashFolder.enabled.
  • com.openexchange.calendar.trashFolder.retentionDays - days an event is kept before the automatic clean-up removes it permanently. Defaults to 30; 0 or below switches the clean-up off.
  • com.openexchange.caldav.trashFolder.enabled - whether CalDAV deletions are soft deletions as well. Defaults to false.

Where the feature is switched on, deleting an appointment becomes recoverable for the users concerned, and deleted appointments occupy quota until the retention window expires. Switched off again for a user who already has entries in the Trash, the folder leaves the folder tree and deletes are permanent again, while the entries are kept and the clean-up leaves them alone; both are back once the feature is on again.

The CalDAV switch is a separate decision: with only the first property on, App Suite deletions go to the Trash while a synchronizing client's deletions remain permanent. That split is deliberate.

With the feature enabled, a Trash folder appears in the user's folder tree on their first deletion and the calendar_trash capability is announced to clients. The retention default is overridden per user through the chronos/trashRetentionDays setting of the io.ox/calendar JSlob; the clean-up runs without a session, so a value defined per host name (as-config.yaml) does not apply to it.

A shared account's Trash folder is purged by the account's own retention, not by the acting deputy's. The io.ox/calendar JSlob hands it out per account under sharedaccount/<account id>/chronos/trashRetentionDays, next to trashFolderId; a deputy holding the writeJSlob capability for the account may change it there.

CalDAV has no equivalent of the HTTP API's harddelete parameter, so one switch answers for every deletion the protocol can express. It can only withhold the Trash from CalDAV, never grant it.

See the configuration documentation, as well as the "Trash Folder / Soft Delete" section of the calendar implementation details for further details.

Database

SCR-2211

Summary: New column pool in table mail_credential for pooled mail credentials

Effective: 8.55.481 and later

Update Task com.openexchange.mail.credential.impl.groupware.MailCredentialAddPoolColumnTask

The update task com.openexchange.mail.credential.impl.groupware.MailCredentialAddPoolColumnTask adds the nullable column pool (BINARY(16)) and the key pool to the table mail_credential. Through it, a kept mail credential refers to the pooled credential of its user, see com.openexchange.mail.credential.pooling. A referring row keeps its own copy, so earlier versions use it as before. Existing rows get NULL and are used as before.

SCR-2203

Summary: New indexes on (cid, id) in table login2user and on (alias, cid) in table user_alias

Effective: 8.55.481 and later

Update Task com.openexchange.groupware.update.tasks.Login2UserAddIdIndexTask

The update task adds the index id over (cid, id) to the table login2user in the user databases. The primary key covers (cid, uid) only, so each lookup of a login by user identifier reads all rows of the context: when loading users, in the provisioning user search and in getMultipleData.

In a context with 3,000 users, a pattern search spent 1.4 seconds in the database alone. Schemas that already have an index on exactly these columns, under any name, keep it. The index holds two integer columns per user and is created online.

A second update task adds the index alias over (alias, cid) to the table user_alias. Its primary key leads with the user, so each lookup of a user by alias read all aliases of the context, and the mail mapping read all aliases of the schema. In a context with 10,000 aliases, a lookup now reads one row instead of 10,010. Here, too, an existing index on exactly these columns is kept.

SCR-2196

Summary: New tables user_recovery_details and user_recovery_email_index for account recovery

Effective: 8.55.481 and later

Update Task com.openexchange.account.recovery.rdb.groupware.RecoveryDetailsCreateTableTask, com.openexchange.account.recovery.rdb.groupware.RecoveryEmailIndexBackfillTask

  • user\_recovery\_details in every groupware schema holds a user's recovery email, phone and PIN with their verification state. The update task com.openexchange.account.recovery.rdb.groupware.RecoveryDetailsCreateTableTask creates it. The task runs only while com.openexchange.accountrecovery.enabled=true.
  • user\_recovery\_email\_index in the ConfigDB holds a copy of every recovery email, with the columns cid, id and recovery\_email. With it the public lookup costs one query instead of one per schema.
  • The Liquibase change log accountRecoveryConfigdbChangeLog.xml creates the index table. The update task com.openexchange.account.recovery.rdb.groupware.RecoveryEmailIndexBackfillTask fills it from existing details and rebuilds it when re-run with forceupdatetask.
  • A failed index write is counted in appsuite.account.recovery.index{outcome="failed"}.
  • Deleting a context or a user removes their rows from both tables.

SCR-2181

Summary: New columns for administrative data exports in dataExportTask and dataExportFilestoreLocation

Effective: 8.55.481 and later

Update Task com.openexchange.gdpr.dataexport.impl.groupware.DataExportAddAdministrativeColumnsTask

8.x:dataExportTask:addAdministrativeColumns

To keep an export an administrator starts on behalf of a user apart from the user's own, the update task adds these columns to the user databases, and the changeset 8.x:dataExportTask:addAdministrativeColumns to the global database:

  • dataExportTask: origin (user or admin, default user), caseReference, requestedBy and skippedModules
  • dataExportFilestoreLocation: sha256, the checksum of a result package

The unique key of dataExportTask changes from (cid, user) to (cid, user, origin). The task is idempotent and only alters the data export tables, which hold one row per pending or kept export. Rolling the changeset back deletes the administrative exports.

SCR-2165

Summary: New columns for the rotation of personal access tokens in table access_token

Effective: 8.55.481 and later

Update Task com.openexchange.accesstoken.impl.groupware.AccessTokenAddRotationColumnsTask

The update task com.openexchange.accesstoken.impl.groupware.AccessTokenAddRotationColumnsTask adds the columns rotated, lifetime, previous_hash, previous_key and previous_until and the index previous on (cid, previous_hash) to table access_token. A rotation of a personal access token writes them: when it happened, the lifetime the token was minted with, and the hash and sealed key of the replaced secret together with the end of its grace period. Until the update task has run, access tokens cannot be validated.

SCR-2148

Summary: New column sendAs in table deputy

Effective: 8.55.481 and later

Update Task com.openexchange.deputy.impl.groupware.DeputyStorageAddSendAsColumnTask

The deputy table gains the column sendAs, which stores whether a deputy may send E-Mails as the granting user without a Sender header. Behavior-neutral for existing rows: the default 0 keeps existing deputy permissions with their current "send on behalf of" setting.

ALTER TABLE deputy ADD COLUMN sendAs TINYINT(1) NOT NULL DEFAULT 0;

Fresh schemas: com.openexchange.deputy.impl.groupware.DeputyStorageCreateTableService. Existing schemas: com.openexchange.deputy.impl.groupware.DeputyStorageAddSendAsColumnTask (idempotent, depending on DeputyStorageCreateTableTask). The deputy table is small on typical deployments, so no noticeable ALTER cost is expected.

Note for operators: during a rolling upgrade, nodes of the previous version do not know the column. They delete a deputy permission that grants neither a module nor "send on behalf of" as soon as they read it; a deputy who opens App Suite on such a node is enough. So a deputy permission granting only sendAs without any module must not be created before all nodes run the new version. The same applies after a rollback to a version without 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 the following statement in every context database schema before rolling back; the deputies then send E-Mails on behalf of the granting user, and "send as" has to be granted anew after upgrading again:

UPDATE deputy SET sendOnBehalfOf = 1, sendAs = 0 WHERE sendAs = 1;

SCR-2115

Summary: Added column data to table notificationQueue

Effective: 8.55.481 and later

Update Task com.openexchange.notification.queue.impl.groupware.NotificationQueueAddDataColumnTask

The table notificationQueue gets the new nullable column data (TEXT, utf8mb4) holding a notification's optional structured data. A blocking update task adds it to existing schemas; it is idempotent and runs after NotificationQueueCreateTableTask. New schemas get the column on creation. The ALTER only touches this table, which holds at most 100 pending notifications per user by default.

SCR-2094

Summary: Index refresh_due of table mail_credential now starts with caller_key

Effective: 8.55.481 and later

Update Task com.openexchange.mail.credential.impl.groupware.MailCredentialRefreshDueByCallerKeyTask

The index refresh_due of table mail_credential now spans (caller_key, refresh_due). The update task com.openexchange.mail.credential.impl.groupware.MailCredentialRefreshDueByCallerKeyTask replaces the index and marks rows with refresh_due 0 that hold a credential as due, in batches of 10,000 rows, so the keep-alive picks them up again.

SCR-2087

Summary: New column refresh_due in table mail_credential

Effective: 8.55.481 and later

Update Task com.openexchange.mail.credential.impl.groupware.MailCredentialAddRefreshDueColumnTask

Table mail_credential gets the column refresh_due (BIGINT, default 1) and the indexes refresh_due and id, added by the update task com.openexchange.mail.credential.impl.groupware.MailCredentialAddRefreshDueColumnTask without rewriting existing rows. The column holds when kept OAuth tokens are due for a keep-alive, or -1 once the identity provider rejected their refresh token. Run the update tasks of a schema before nodes of this release serve it: every access to a kept credential reads the column.

SCR-2083

Summary: New column folders in table access_token

Effective: 8.55.481 and later

Update Task com.openexchange.accesstoken.impl.groupware.AccessTokenAddFoldersColumnTask

The update task com.openexchange.accesstoken.impl.groupware.AccessTokenAddFoldersColumnTask adds the nullable TEXT column folders to table access_token. It holds the folder restriction of a personal access token; existing tokens stay unrestricted. A restricted token is stored under a hash that earlier versions do not look up, so after a rollback it is refused instead of accepted without restriction.

SCR-2079

Summary: New table mcp_activity

Effective: 8.55.481 and later

Update Task com.openexchange.mcp.activity.ActivityCreateTableTask

The new table mcp_activity in every user database schema holds the calls made through access tokens at /mcp, for their owners: context, user, grant, time, client, tool, object identifiers, mode and outcome, never content. The update task com.openexchange.mcp.activity.ActivityCreateTableTask creates it. Rows go with their token, user and context; an hourly clean-up keeps the table within com.openexchange.mcp.activity.retentionDays and com.openexchange.mcp.activity.maxEntriesPerToken.

SCR-2035

Summary: Added index on the targeted shared account

Effective: 8.55.481 and later

Update Task com.openexchange.sharedaccount.storage.rdb.groupware.SharedAccountAddTargetIndexTask

Deleting a context or user removes the shared account permissions and user settings that target its shared accounts. Without a matching index this scanned and locked the whole table, so every insert into it waited until the deletion ended and could fail with a socket time-out. A new index sharedaccount_target on (sharedaccount_cid, sharedaccount_user) is added to the tables sharedaccount_permissions and sharedaccount_usersettings. Existing schemas get it through the update task; the ALTER TABLE runs online, but may take a while on large tables.

SCR-1872

Summary: New Trash Marker Columns in the Calendar Tables

Effective: 8.55.481 and later

Update Task com.openexchange.chronos.storage.rdb.groupware.CalendarAddTrashColumnsTask

The calendar Trash folder records what was soft-deleted, by whom and where it came from on the rows themselves. The columns are applied by the update task com.openexchange.chronos.storage.rdb.groupware.CalendarAddTrashColumnsTask; freshly created schemas get them from ChronosCreateTableService.

  • calendar_event and calendar_event_tombstone - trashedFrom VARCHAR(255), trashedBy INT4 UNSIGNED, trashedAt BIGINT(20), trashedUid VARCHAR(1024)
  • calendar_attendee and calendar_attendee_tombstone - trashedFrom VARCHAR(255), trashedBy INT4 UNSIGNED, trashedAt BIGINT(20)

All default to NULL, which is what "not in the Trash" means, so existing rows are left as they are and no data is migrated. trashedUid is on the event tables only: it preserves the unique identifier an event gave up on the way in, which is a property of the event rather than of an attendee's view on it.

No index is added, trashedAt being NULL for practically every row; the retention clean-up scans instead. These are the largest tables of the calendar schema, which is worth taking into account when estimating how long the update task runs.

See the "Trash Folder / Soft Delete" section of the calendar implementation details for further details.

Packaging/Bundles

SCR-2193

Summary: New package open-xchange-account-recovery for self-service password reset

Effective: 8.55.481 and later

The middleware gains self-service account recovery. A user who forgot the password asks by recovery email address, primary address or alias, and receives a single-use reset link by mail or SMS. The feature ships in the new package open\-xchange\-account\-recovery with these bundles:

  • com.openexchange.account.recovery
  • com.openexchange.account.recovery.json
  • com.openexchange.account.recovery.rdb
  • com.openexchange.account.recovery.rest

Details:

  • The package stays inactive until com.openexchange.accountrecovery.enabled=true is set. The value is read at bundle start. The core-mw chart disables the package by default. Enable it with features.status.account\-recovery: enabled.
  • Redis is required once the feature is on. Reset tokens and SMS verification codes are stored there, tokens only as a hash.
  • Packages that extend account recovery import its bundles, for example open\-xchange\-cloudplugins\-account\-recovery. Disable the feature with the property, not by removing only the core package. Otherwise the middleware never becomes ready.
  • Documentation: documentation/login\_and\_sessions/account\_recovery.md.

SCR-2182

Summary: Added bundle com.openexchange.external.authentication.multifactor

Effective: 8.55.481 and later

The external authentication no longer requires the optional package open-xchange-multifactor. Until now, the bundle com.openexchange.external.authentication did not start without it. Its multifactor end-point /authentication/v1/multifactor moved into a bundle of its own:

  • com.openexchange.external.authentication.multifactor, shipped with the package open-xchange-multifactor

With the multifactor package installed, nothing changes. Without it, the external authentication starts and the multifactor end-point is not available.

SCR-2164

Summary: New package open-xchange-guard-backend-plugin-cassandra for the OX Guard token storage under external authentication

Effective: 8.55.481 and later

The Cassandra storage of the OX Guard authentication tokens of external sessions moved out of the bundle com.openexchange.guard.client into the new bundle com.openexchange.guard.client.cassandra, shipped with the new package open-xchange-guard-backend-plugin-cassandra. The OX Guard client therefore no longer depends on open-xchange-cassandra.

The package is disabled by default in the core-mw chart. Deployments with external authentication have to enable it along with open-xchange-cassandra:

packages:
  status:
    open-xchange-cassandra: enabled
    open-xchange-guard-backend-plugin-cassandra: enabled

Under external authentication the OX Guard client registers its services only once such a token storage is available, so without the package OX Guard is unavailable. Classic deployments require no action.

SCR-2063

Summary: New bundles for external authentication, the no-op session store and session obfuscation

Effective: 8.55.481 and later

Added the following bundles to the open-xchange-core package:

  • com.openexchange.external.authentication.utils - shared helpers of the external authentication bundles
  • com.openexchange.sessiond.noop - a session store that keeps nothing, active only while external authentication is enabled
  • com.openexchange.session.obfuscation - the obfuscation of session secrets, moved out of com.openexchange.sessiond.redis and provided as ObfuscatorService to any session store

The property com.openexchange.sessiond.encryptionKey keeps its name and meaning; no operator action is required.

SCR-2059

Summary: Added the Bundle com.openexchange.contact.provider.crosscontext

Effective: 8.55.481 and later

New OSGi bundle com.openexchange.contact.provider.crosscontext, shipped in open-xchange-core (added to open-xchange-core.psf, no install-list change). It contains the cross-context contacts provider, which surfaces address books shared from other contexts. Activator com.openexchange.contact.provider.crosscontext.osgi.CrossContextContactsProviderActivator.

See the feature documentation for further details.

SCR-2019

Summary: New Bundle com.openexchange.groupware.common.storage for the Shared Calendar and Contacts Account Storage

Effective: 8.55.481 and later

The package open-xchange-core ships the new bundle com.openexchange.groupware.common.storage. It holds the relational account storage that the calendar and contacts stacks now share, instead of the two separate implementations in com.openexchange.chronos.storage.rdb and com.openexchange.contact.storage.rdb.

SCR-2005

Summary: Package open-xchange-mobile-api ships push subscriptions and requires open-xchange-pns-impl

Effective: 8.55.481 and later

The package open-xchange-mobile-api now also ships the bundle com.openexchange.mobile.push, which manages the push subscriptions of Mobile API apps, and requires open-xchange-pns-impl. Installations that deploy the package need open-xchange-pns-impl as well; push credentials for the apps are configured as described in the Mobile API documentation.

SPI (Service Provider Interface)

SCR-2201

Summary: New Java interfaces for account recovery and administrative password changes

Effective: 8.55.481 and later

New services in com.openexchange.account.recovery:

  • RecoveryRequestGuard vetoes recoveries for single users, for example through a block-list. Core ships no guard.
  • RecoveryMailService and RecoverySmsService replace the default notifications and templates when registered with a higher ranking.
  • ResetUrlResolver builds the reset, verification and login links.
  • RecoveryDetailsListener is notified about changed recovery details.
  • RecoveryDetailsService and RecoveryTokenService are the storage services.

New services in com.openexchange.passwordchange.admin:

  • AdminPasswordChangeService changes a password without a session. The database and webhook backends implement it.
  • AdminPasswordChangeRegistry holds the registered backends.

New mail and SMS templates:

  • notify.account\-recovery.request.mail.html.tmpl, notify.account\-recovery.request.mail.txt.tmpl, notify.account\-recovery.request.sms.tmpl
  • notify.account\-recovery.reset.mail.html.tmpl, notify.account\-recovery.reset.mail.txt.tmpl, notify.account\-recovery.reset.sms.tmpl
  • notify.account\-recovery.verify.mail.html.tmpl, notify.account\-recovery.verify.mail.txt.tmpl, notify.account\-recovery.verify.sms.tmpl

8.54.320

3rd Party Libraries/License Change

SCR-1920

Summary: Upgraded the Equinox OSGi framework from 3.24.200 to 3.24.300

Effective: 8.54.320 and later

Upgraded the Equinox OSGi framework in the target platform from 3.24.200 to 3.24.300. The bundle symbolic name and all exported packages are unchanged; the jar is the upstream artifact, byte-identical to the one published on Maven Central.

The file name carries the bundle version, so every place that names it explicitly moves with it:

  • oxscripts/sbin/open-xchange.in and open-xchange-cloud.in — the OSGI_JAR the service scripts start,
  • docker/go/open-xchange/core/entrypoint/core/start.go — the same path in the container entry point,
  • openexchange-test/.classpath and com.openexchange.bundles/3rdPartyLibs.properties.

The obsolete org.osgi.annotation 6.0.0 bundle is removed alongside. It dates from 2014 and contains only the four annotations of org.osgi.annotation.versioning, which the platform already ships properly in org.osgi.annotation.versioning 1.1.2. No operator action is required.

SCR-1913

Summary: Upgraded the Bean Validation API from 1.1.0.Final to 2.0.1.Final

Effective: 8.54.320 and later

Upgraded the Bean Validation API in the target platform from 1.1.0.Final to 2.0.1.Final. The bundle symbolic name stays javax.validation.api, but the eight exported packages now carry version 2.0.1.Final, and javax.validation.valueextraction is exported in addition.

The upgrade is additive: no class and no member was removed between the two versions, 37 classes were added, and ConstraintValidator.initialize changed from abstract to a default method. Every consumer that imports these packages resolves against 2.0.1 as well — the ranges in use are [1.1,3), [2.0,3) and [2.0.0,3.0.0), plus imports without a range.

It also closes an existing gap. App Suite Office compiles against Bean Validation 2.0.2, which it ships itself, and uses types that 1.1.0 does not contain at all (for example ClockProvider and NotBlank), while its bundles were wired to the platform's 1.1.0 export at runtime.

No configuration change and no operator action are required.

SCR-1905

Summary: Upgraded Apache Tika from 3.3.1 to 4.0.0

Effective: 8.54.320 and later

Upgraded tika-core from 3.3.1 to 4.0.0 in bundle com.openexchange.tika.util. Tika stays fully encapsulated — the bundle exports only com.openexchange.tika.util — so the major upgrade is invisible to consumers and MIME type detection is unchanged.

The 4.0 API required three adjustments inside the wrapper:

  • TikaConfig was replaced by a JSON-based configuration. The parameterless Tika() constructor yields the same defaults the removed Tika(TikaConfig) call produced.
  • Detector.detect now takes a TikaInputStream and a ParseContext instead of a plain InputStream.
  • The HTTP header constants moved from Metadata to HttpHeaders and changed from String to Property.

Tika 4 declares commonmark as a dependency for its Markdown output handler, which this bundle never uses, so those three jars are not embedded. No operator action is required.

SCR-1899

Summary: Upgraded eight third-party libraries to their latest patch or minor release

Effective: 8.54.320 and later

Upgraded eight third-party libraries to their latest patch or minor release. No API or configuration change; no operator action is required.

  • SLF4J and its JCL, JUL, log4j and OSGi bridges from 2.0.18 to 2.0.19 in the target platform.
  • Micrometer from 1.17.0 to 1.17.1 in com.openexchange.metrics.micrometer (also raises the embedded micrometer-commons and micrometer-observation).
  • Spring Beans and Spring Core from 7.0.8 to 7.0.9 in com.openexchange.xml.
  • httpclient5-cache from 5.6.2 to 5.6.4 in com.openexchange.saml, matching the HttpClient 5 version the target platform ships.
  • CBOR from 4.5.2 to 4.5.6 in com.openexchange.webauthn, matching com.openexchange.multifactor.provider.webauthn. The release moved its string utilities into datautilities, which is now embedded alongside it.
  • JavaCC from 7.0.12 to 7.0.13, Mockito from 3.12.4 to 5.23.0 and Jackson Datatype Joda from 2.11.0 to 2.22.2 — build- and test-time only, not shipped.

SCR-1896

Summary: Upgraded the embedded S3 encryption client from 3.6.1 to 4.0.2

Effective: 8.54.320 and later

Upgraded amazon-s3-encryption-client-java from 3.6.1 to 4.0.2 in bundle software.amazon.awssdk.

  • amazon-s3-encryption-client-java-3.6.1.jar is replaced by amazon-s3-encryption-client-java-4.0.2.jar; no exported package changes.
  • Version 4.0 removes S3EncryptionClient.builder(). The client is now created via builderV4() with the commitment policy pinned to FORBID_ENCRYPT_ALLOW_DECRYPT and the algorithm suite to ALG_AES_256_GCM_IV12_TAG16_NO_KDF.

The stored object format is unchanged: objects written before the upgrade stay readable, newly written objects stay readable by earlier App Suite versions, and no data migration is required. Without the pinned settings the 4.0 default of key commitment with REQUIRE_ENCRYPT_REQUIRE_DECRYPT would reject every previously written encrypted object.

SCR-1895

Summary: Upgraded the embedded SAAJ implementation from 2.0.1 to 3.0.6

Effective: 8.54.320 and later

Upgraded the embedded SAAJ implementation in software.amazon.awssdk from 2.0.1 to 3.0.6, the version that com.openexchange.soap.common already ships. Both bundles now embed the same version.

The jar is embedded because the S3 encryption client uses com.sun.xml.messaging.saaj.packaging.mime.internet.MimeUtility to decode content metadata; nothing else in the bundle touches SAAJ. That class has an identical public API in both versions and depends only on jakarta.activation, which the platform provides. No operator action is required.

SCR-1894

Summary: Upgraded the Kotlin OSGi bundle from 2.4.10 to 2.4.20

Effective: 8.54.320 and later

Upgraded the Kotlin OSGi bundle in the target platform from 2.4.10 to 2.4.20, replacing kotlin-osgi-bundle-2.4.10.jar with kotlin-osgi-bundle-2.4.20.jar.

The bundle keeps its symbolic name org.jetbrains.kotlin.osgi-bundle; the exported packages move from version 2.4.10 to 2.4.20 and gain kotlin.coroutines.debug. No package was removed. The two consuming bundles import the Kotlin packages without a version range, so no operator action is required.

SCR-1893

Summary: Upgraded embedded third-party libraries in 20 bundles

Effective: 8.54.320 and later

Upgraded embedded third-party libraries in 20 bundles. All are minor or patch releases within the same major version.

  • AWS SDK for Java 2.46.21 to 2.55.1 in software.amazon.awssdk
  • Kubernetes Client 7.8.0 to 7.9.0 in io.fabric8.kubernetes
  • Guava 33.6.0-jre to 33.7.1-jre and Caffeine 3.2.4 to 3.3.0 in com.google.guava
  • Nimbus OAuth 2.0 SDK 11.37.2 to 11.38.2 in com.nimbus
  • SnakeYAML 2.6 to 2.7 in org.yaml.snakeyaml
  • libphonenumber 9.0.34 to 9.0.39 in com.openexchange.sms
  • Liquibase 5.0.3 to 5.0.4 in liquibase.core
  • GeoIP2 5.1.0 to 5.2.0 and MaxMind DB 4.1.0 to 4.2.0 in com.openexchange.geolocation.maxmind.binary; MaxMind DB 4.2.0 rejects crafted databases beyond new decoder limits, regular lookups stay far below them
  • Box Java SDK 10.15.1 to 10.17.0 in com.openexchange.file.storage.boxcom; commons-codec, now required by the SDK, is imported from the target platform
  • Jolokia 2.6.0 to 2.6.3 in com.openexchange.jolokia
  • prometheus-metrics 1.7.0 to 1.9.0 in com.openexchange.metrics.micrometer, now at one version across all embedded prometheus-metrics-* jars

  • and further minor and patch updates to metadata-extractor, Dropbox SDK, Woodstox, Dropwizard Metrics, jTNEF, Xalan serializer, brownies-collections and jackson-datatype-joda

The jar file names listed in each bundle's Bundle-ClassPath and 3rdPartyLibs.properties change accordingly. No artifact was added to or removed from any embed set, and no operator action is required.

SCR-1891

Summary: Upgraded the embedded TwelveMonkeys, Apache CXF, Google API Client, Jetty and OkHttp libraries

Effective: 8.54.320 and later

Upgraded the third-party libraries embedded in five bundles.

  • TwelveMonkeys ImageIO 3.13.1 to 3.15.2 in com.openexchange.imagetransformation.java; 3.15.1 and 3.15.2 harden the IFF, PICT and PSD decoders against crafted files
  • Apache CXF 4.2.2 to 4.2.3 in com.openexchange.soap.common
  • Google API Client in com.google.api.client: google-http-client 2.1.1 to 2.2.0, google-api-client 2.9.0 to 2.9.1, google-auth-library-oauth2-http 1.47.0 to 1.52.0, api-common 2.65.0 to 2.68.0, and the Calendar, Drive and Gmail service APIs
  • Jetty 12.1.12 to 12.1.13 in com.openexchange.http.jetty
  • OkHttp 5.4.0 to 5.5.0 in com.squareup.okhttp3, which also updates the embedded okio-jvm from 3.17.0 to 3.18.1

The jar file names listed in each bundle's Bundle-ClassPath and 3rdPartyLibs.properties change accordingly. The newer Google libraries add jspecify-1.0.0.jar as a further embedded artifact. No operator action is required.

SCR-1870

Summary: Upgraded Jackrabbit WebDAV from 2.21.19 to 2.22.4 in target platform

Effective: 8.54.320 and later

The Jackrabbit WebDAV client library (jackrabbit-webdav) is upgraded from 2.21.19 to 2.22.4 in the target platform. Our copy stays re-wrapped: the bundle's Import-Package range for javax.servlet and javax.servlet.http is widened from the upstream [3.1,4) to [4,5), because the platform exports javax.servlet 4.0.0, which the upstream range excludes. Exported packages and their versions are unchanged, and the library is used internally by the WebDAV file storage and DAV subscription bundles only. No admin action.

SCR-1869

Summary: Upgraded Logback from 1.5.38 to 1.6.3 in target platform

Effective: 8.54.320 and later

Logback (logback-classic, logback-core) is upgraded from 1.5.38 to 1.6.3 in the target platform. The only configuration element that disappears is the long deprecated ch.qos.logback.classic.turbo.ReconfigureOnChangeFilter. The configurations shipped with the middleware do not use it, but a logback.xml that still declares it as a <turboFilter> has to drop that element and rely on the scan attribute instead. No other Joran action, model or appender was removed. No admin action otherwise.

SCR-1867

Summary: Upgraded MySQL Connector/J from 9.7.0 to 26.7.0 in target platform

Effective: 8.54.320 and later

Upgraded the MySQL JDBC driver in the target platform (com.openexchange.bundles): mysql-connector-j 9.7.0 to 26.7.0.

The jump in the version number is a change of the upstream versioning scheme, not a rewrite: 26.7.0 is the release that directly follows 9.7.0, with no version in between. Bundle symbolic name (com.mysql.cj), the 27 exported packages and the JDBC driver class (com.mysql.cj.jdbc.Driver) are unchanged, and every consumer imports the driver packages without a version range, so the exported package versions moving from 9.7.0 to 26.7.0 affects nobody. No source change was required.

Compatibility with MariaDB — the only supported database — was verified against MariaDB 10.11.19: reading (folders, mail, calendar, contacts, capabilities, quota) and a full write cycle (insert, select, update, delete of a task) both work, with no SQL exception of any kind in the log.

SCR-1866

Summary: Upgraded Kotlin OSGi bundle and Equinox Configuration Admin in target platform, added the OSGi Coordinator API

Effective: 8.54.320 and later

Upgraded two libraries in the target platform (com.openexchange.bundles):

  • kotlin-osgi-bundle 2.2.21 to 2.4.10
  • org.eclipse.equinox.cm 1.4.100 to 1.6.400

Equinox Configuration Admin 1.6.x adds a mandatory import of org.osgi.service.coordinator;version="[1.0.0,2.0.0)", which no bundle in the target platform provided. The OSGi Coordinator API bundle org.osgi.service.coordinator 1.0.2 is therefore added alongside it; without it the org.eclipse.equinox.cm bundle would not resolve.

The Kotlin upgrade moves the exported package versions from 2.2.21 to 2.4.10 for all 116 packages. That is safe here because every consumer -- com.squareup.okhttp3 and com.openexchange.jmap -- imports the Kotlin packages without a version range.

SCR-1865

Summary: Upgraded commons-collections4, commons-validator, javassist, jctools, joda-time, jakarta.validation-api, xmlunit, protobuf-java, HK2, Logback, SPI Fly and Apache mime4j in target platform

Effective: 8.54.320 and later

Routine upgrades of third-party libraries in the target platform (com.openexchange.bundles). No source change was required.

  • commons-collections4 4.5.0 to 4.6.0
  • commons-validator 1.10.1 to 1.11.0
  • javassist 3.32.0-GA to 3.33.0-GA
  • jctools-core 4.0.6 to 4.0.7
  • joda-time 2.14.2 to 2.14.4
  • jakarta.validation-api 3.1.0 to 3.1.1
  • xmlunit-core 2.10.0 to 2.14.0
  • protobuf-java 4.35.1 to 4.36.2
  • hk2-api, hk2-locator, hk2-utils and aopalliance-repackaged 4.0.1 to 4.0.2
  • glassfish-corba-omgapi 5.0.0 to 5.0.2
  • logback-classic and logback-core 1.5.37 to 1.5.38; both keep importing org.slf4j;version="[2.0,3)", so SLF4J stays at 2.0.18
  • org.apache.aries.spifly.dynamic.bundle 1.3.7 to 1.3.8; it now requires ASM 9.10 and OSGi Core R8, both provided by the target platform
  • apache-mime4j-core, apache-mime4j-dom and apache-mime4j-storage 0.8.14 to 0.8.15

As before, glassfish-corba-omgapi is re-wrapped so that the specification packages javax.rmi and javax.rmi.CORBA are exported at the specification version 1.0.0 rather than at the bundle version. Without that, jdo-api cannot satisfy its javax.rmi;version="[1.0,2)" import and the javax.jdo bundle stops resolving.

Apache mime4j 0.8.15 adds default parsing limits: at most 512 MIME parts, a nesting depth of 64, 16384 header fields and 1 MiB of header data per message. Mail import (mail?action=import) parses strictly by default, so a message beyond these limits is now rejected with MSG-0101; with strictParsing=false it is still imported.

SCR-1864

Summary: Upgraded BouncyCastle, Jackson, PDFBox, jsoup, HttpClient5, FreeMarker, Commons Codec and snappy-java in target platform

Effective: 8.54.320 and later

Upgraded third-party libraries in the target platform (com.openexchange.bundles):

  • bcmail-jdk18on, bcpg-jdk18on, bcpkix-jdk18on and bcutil-jdk18on upgraded from 1.84 to 1.86, bcprov-jdk18on from 1.84 to 1.86
  • jackson-core, jackson-databind, the jackson-dataformat-*, jackson-datatype-*, jackson-jakarta-rs-* and jackson-module-* jars upgraded from 2.22.0 to 2.22.2 (jackson-annotations stays at 2.22, no patch release exists)

  • pdfbox, pdfbox-io, fontbox and xmpbox upgraded from 3.0.7 to 3.0.8

  • jsoup upgraded from 1.22.2 to 1.23.2

  • httpclient5 upgraded from 5.6.2 to 5.6.4; httpcore5 stays at 5.4.3, the version HttpClient 5.6.4 is built against

  • freemarker upgraded from 2.3.34 to 2.3.35

  • commons-codec upgraded from 1.22.0 to 1.22.1

  • snappy-java upgraded from 1.1.10.7 to 1.1.10.8

BouncyCastle 1.85 removed the sample-code packages org.bouncycastle.crypto.examples, org.bouncycastle.mail.smime.examples and org.bouncycastle.openpgp.examples, and removed org.bouncycastle.iana; org.bouncycastle.asn1.iana moved from bcutil to bcprov. The stale (unused) imports of org.bouncycastle.crypto.examples and org.bouncycastle.iana were removed from the com.openexchange.saml bundle manifest. FreeMarker 2.3.35 dropped freemarker.debug and freemarker.debug.impl, which no bundle imports. No source change was required.

BouncyCastle 1.86 fixes 13 CVEs, among them OpenPGP subkey certification and SEIPDv1 truncation, CMS AuthenticatedData and the NameConstraints check on end-entity certificates in PKIXCertPathReviewer. It introduces default limits: S/MIME nesting depth 64 (org.bouncycastle.mime.max_depth), PBKDF2 iteration count 10,000,000 (org.bouncycastle.pbe.max_iteration_count) and 262,144 nodes when building certificate paths (org.bouncycastle.x509.max_cert_path_build_nodes). It also removes legacy post-quantum packages from bcprov such as org.bouncycastle.pqc.crypto.mlkem and org.bouncycastle.pqc.jcajce.provider.kyber; no bundle imports them.

SCR-1863

Summary: Updated Netty libraries from v4.2.16 to v4.2.18 in bundle io.netty and Lettuce from v7.6.0 to v7.7.0 in bundle io.lettuce

Effective: 8.54.320 and later

Upgraded Netty from v4.2.16.Final to v4.2.18.Final and netty-tcnative-classes from v2.0.80.Final to v2.0.84.Final in bundle io.netty, and Lettuce from v7.6.0.RELEASE to v7.7.0.RELEASE together with reactor-core from v3.8.6 to v3.8.7 in bundle io.lettuce. The Netty update fixes CVE-2026-59903, a cache poisoning and information disclosure issue in netty-codec-http, as well as several further security advisories affecting netty-codec-http and netty-codec-http2 (resource exhaustion, header validation, request smuggling). Bundle io.lettuce now also exports the new packages io.lettuce.core.probabilistic and io.lettuce.core.probabilistic.arguments; no packages were removed. No admin action.

API - HTTP-API

SCR-1995

Summary: New Mobile API for native mail apps at /mobile/v1

Effective: 8.54.320 and later

The middleware serves a resource-oriented HTTP API for native mail apps at /mobile/v1, described by its own OpenAPI document. This release brings the foundation every operation builds on; the mail operations follow.

  • Every request carries a bearer token. A deployment signs in either with personal access tokens (oxa_…) or with the operator's identity provider, never with both; a token of the other kind is answered with 401.
  • GET /mobile/v1/auth/config needs no token and tells a client which of the two modes applies and what it needs for it.
  • Errors are application/problem+json (RFC 9457) with a stable { ```text } clients switch on, the middleware's own error code as and the request's tracking identifier as . * Every also answers . An unknown path is 404, a known path with another method 405 with . * answers 304. The write operations that follow will answer 428 without and 412 with the current representation when it is stale.

The API answers only where is set, and it needs the OAuth provider to validate tokens. Existing endpoints are unaffected. ```

SCR-1993

Summary: New header Idempotency-Key and parameter clientMessageId to send a mail at most once

Effective: 8.54.320 and later

The requests POST /mail?action=new, POST /mail/compose/{id}/send and PUT /mail?action=transport accept the header Idempotency-Key: a retry with the same key is not performed again, but answered with the kept result of the first request and the response header Idempotent-Replayed: true. A client can also pick a UUID per mail and pass it as clientMessageId when opening the composition space (POST /mail/compose), when sending, or as field of mail?action=new. The Message-ID header is built from it, and a later send of the same mail returns the first result with the response field duplicate set to true. New error codes IDEM-0001 to IDEM-0007; the REST API answers them with status 400, 409 or 422. Purely additive; requests without the header or the parameter behave as before.

SCR-1991

Summary: New login actions accessToken and accessTokenSecondFactor to sign in for a personal access token

Effective: 8.54.320 and later

POST <dispatcher prefix>login?action=accessToken lets a client without a browser sign in with user name and password (JSON body with login, password and the optional label, scopes and expires) and answers like accesstoken?action=new: with the token's metadata and, once, its secret. The sign-in runs the regular login with a transient session; no cookie is set and no session remains. App passwords and guest credentials are refused. A user with a second factor gets the error ACCESSTOKEN-0012 with a challenge (challengeId, expiresAt, factors) as data and confirms it with POST <dispatcher prefix>login?action=accessTokenSecondFactor (challengeId, provider, deviceId, secret_code) without sending the password again; only authenticator apps, backup strings and SMS are offered. Attempts are limited per login name, client address and user (LGI-0028, ACCESSTOKEN-0017). Both actions are off unless com.openexchange.accesstoken.signin.enabled is set; other bundles get the same sign-in through the OSGi service AccessTokenSignInService. Purely additive.

SCR-1977

Summary: New parameter pushToken for changing mail requests

Effective: 8.54.320 and later

Changes to mail and mail folders made through the middleware are now published as push notifications with the new topics ox:mail:changed, ox:mail:deleted and ox:mail:folder. Existing subscriptions to * or ox:mail:* receive them, too. To keep a client from being notified about its own changes, the following requests accept the new optional query parameter pushToken, the client's push token; the subscription with this token is skipped.

  • PUT /mail?action=update
  • PUT /mail?action=flags
  • PUT /mail?action=color_label
  • PUT /mail?action=copy
  • PUT /mail?action=copy_multiple
  • PUT /mail?action=move
  • PUT /mail?action=move_all
  • PUT /mail?action=delete
  • PUT /mail?action=expunge
  • PUT /mail?action=clear
  • POST /mail?action=new and PUT /mail?action=new
  • PUT /mail?action=autosave

The folders requests new, update, delete and clear already accept pushToken; it now applies to mail folder notifications as well. Requests without the parameter behave as before.

See the HTTP API documentation for further details.

SCR-1974

Summary: New capabilities access_tokens and mcp

Effective: 8.54.320 and later

Two new capabilities tell a client what to offer before it calls anything.

access_tokens is awarded to a user who may mint personal access tokens: the user is neither a guest nor anonymous, and the OAuth provider is enabled for the user. These are the checks the accesstoken module applies before minting, so a settings page shown only with this capability never offers what the module would refuse.

mcp is awarded to a user who can use the MCP endpoint: the endpoint is registered on the node, the user is neither a guest nor anonymous, and the OAuth provider is enabled for the user. It is independent of access_tokens, since personal access tokens serve more than the MCP endpoint and an MCP client may also bring a token from an external authorization server.

No admin action. access_tokens follows com.openexchange.oauth.provider.enabled; mcp also follows com.openexchange.mcp.enabled and whether the open-xchange-mcp package is installed.

SCR-1946

Summary: New HTTP API module accesstoken for personal access tokens

Effective: 8.54.320 and later

The new module accesstoken lets a user mint bearer tokens for clients that cannot run an OAuth flow, such as a script or an MCP client with a fixed Authorization header: new (parameters label, scopes, expires) returns the token metadata and, once, the secret oxa_<context-id>_<random>; all lists the user's tokens together with the scopes the user may grant (grantable_scopes, each as scope and description); delete revokes one. The actions require a full session of a regular user: a session made from a token cannot mint tokens, and guest users cannot mint tokens at all (ACCESSTOKEN-0004). The module is registered only while the OAuth provider is enabled, and minting is refused where the provider is disabled for the user (ACCESSTOKEN-0005). The bundles com.openexchange.accesstoken (API), com.openexchange.accesstoken.impl (storage, validator plug-in, clean-up, password-change handler, mail guard) and com.openexchange.accesstoken.json (the module) ship in the package open-xchange-core, since the tokens are a bearer credential for every OAuth-protected endpoint.

A token is bound to its user and limited to the scopes chosen at minting. The grantable scopes are the ones the installed modules register with the OAuth provider (OAuthScopeProvider, e.g. read_contacts, write_contacts, read_mail, read_calendar), offered only where the user's capabilities admit the module. Two limits apply, both configurable (com.openexchange.accesstoken.maxLifetimeDays, default 365, and com.openexchange.accesstoken.maxTokensPerUser, default 50). The token is accepted as bearer token by every endpoint that validates tokens through the OAuth provider; the HTTP API modules with restricted actions take it in place of the session parameter. A request outside the token's scopes is 403 with insufficient_scope; an unknown or revoked token is 401 with invalid_token, an expired one 401 with a description naming the expiry; when the token cannot be checked because the database is unavailable, the answer is 503 with temporarily_unavailable and the client keeps its token.

For mail access the token stores no credential of its own: minting asks the mail credential vault (feature access-token) to keep what the session provides, sealed with the token's secret, and the listing reports whether it did as mail_access. Under master authentication (com.openexchange.mail.passwordSource=global) the vault records that nothing is needed, so mail_access is true; a session without password or OAuth tokens mints a token with mail_access false, and such a token never reaches the mail server. A password change the user makes through App Suite revokes every token of the user; a password set through provisioning does not, since that path posts no password-change event. A token minted without mail credential is refused at the mail server with ACCESSTOKEN-0008 instead of presenting its secret there. Expired tokens are dropped by a clean-up job a week after their expiry.

SCR-1936

Summary: Soft-Deleted Attendees Marked with a Read-Only Extended Parameter in the Calendar HTTP API

Effective: 8.54.320 and later

The calendar HTTP API now marks a soft-deleted user (pending deletion) that appears as an attendee of an existing appointment, so a client can tell a leaver apart from an ordinary external participant.

When another participant loads an event a soft-deleted user is invited to, the user is resolved to an external attendee: the display name and address are kept, but the internal entity reference is dropped (the appointment data itself is not modified). Such an attendee now carries the read-only extended parameter X-OX-SOFT-DELETED in its extendedParameters object, whose value is the time of the soft-deletion in milliseconds since the epoch (UTC).

The marker is applied on read only: it is never written to the storage, and it is left out of exported iCal data, so it does not reach CalDAV clients. It is surfaced through the existing extendedParameters field, so no new attribute is introduced in the schema.

The organizer of an event keeps its internal reference and is therefore not marked - this preserves the ability to hand an appointment to another user through the change-organizer operation; the organizer's soft-deleted state stays resolvable through the user's soft_deleted attribute (SCR-1933).

See the Soft-deleted users documentation, as well as the HTTP API documentation for further details.

SCR-1933

Summary: Soft-deleted user state visible in the HTTP API

Effective: 8.54.320 and later

The user module renders the new attribute soft_deleted (column 628), the time a user has been soft-deleted in milliseconds since the epoch (UTC, not shifted by the user's time zone); absent for every other user. Soft-deleted users stay absent from users?action=all and users?action=search, a users?action=get with the identifier answers with the attribute set. A login of a soft-deleted user is refused with AUTHORIZATION-0004 ("The account is disabled and pending deletion") instead of AUTHORIZATION-0001. Lets a client tell a leaver apart from a disabled account.

SCR-1887

Summary: New Attribute classifiedAccess for Deputy Permissions to See Confidential Appointments

Effective: 8.54.320 and later

A granting user can now allow a deputy to see appointments marked as confidential in the shared calendar folders with all details, independently of the deputy attending them. The deputy permission gained the optional attribute classifiedAccess next to sendOnBehalfOf, accepted by PUT /ajax/deputy?action=new and PUT /ajax/deputy?action=update and reported back by action=get, action=all and action=reverse. Like sendOnBehalfOf it is an attribute of the whole deputy permission, but it exclusively concerns the calendar:

  • none (default) - classified appointments are anonymized (confidential) or hidden (private), as for any other user the calendar is shared with
  • confidential - appointments marked as confidential are shown with all details

Appointments marked as private always stay hidden from deputies.

Example request:

{
  "userId": 4,
  "folderMode": "default",
  "classifiedAccess": "confidential",
  "modulePermissions": {
    "calendar": {
      "permission": 257
    }
  }
}

The right applies to the calendar folders covered by the deputy permission. Together with the granted folder permission, the deputy may also edit and delete confidential appointments, classify appointments as confidential or back as public, and create confidential appointments in those folders; attachments as well as the details of confidential appointments in free/busy results and conflict checks follow the same rule, and the appointments keep their private / confidential event flags. On update, the attribute is only changed when 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. The attribute is omitted in responses when not granted, so existing grants serialize as before.

Purely additive - existing requests and grants are unaffected. Known limitation: granting or revoking the right modifies no appointment, so clients synchronizing the shared calendar incrementally (action=updates, CalDAV, EAS) only pick up the changed visibility with their next full synchronization.

See the feature documentation and the HTTP API documentation for further details.

SCR-1878

Summary: New vacation rule fields "vacationMode", "subjectExt" and "textExt" to treat internal and external senders differently

Effective: 8.54.320 and later

The vacation action command of the mail filter v2 HTTP API (mailfilter/v2?action=new and action=update) gains fields that let the vacation notice answer internal and external senders differently:

  • vacationMode — the explicit mode: all (every sender receives the same notice — the classic rule), split (external senders receive the separate external text/subject) or internalOnly (only internal senders receive a notice)

  • textExt / subjectExt — the text and subject for external senders in mode split; textExt is required by that mode, and without subjectExt external senders get the auto-generated subject of RFC 5230, never the internal one

{"actioncmds":[{"id":"vacation","days":"7","vacationMode":"split","subject":"Out of office","text":"Back in 10 days.","subjectExt":"Out of office","textExt":"Your message will be forwarded.","from":["anton@example.com"]}]}

The client contract on vacationMode: clients supporting the new fields MUST send it on every write of a vacation action — including when the feature is not announced. all is always accepted, and an existing extended rule stays editable with its modes: while the feature is unavailable, clients echo the mode they read and offer the downgrade to all only as an explicit user choice with a warning — availability can also flip temporarily on a configuration mistake, and a routine edit must not degrade the rule. A vacation action WITHOUT vacationMode is treated as written by a client unaware of the fields: an existing internal/external structure of the rule is preserved across the otherwise complete replace instead of being silently stripped. The contract only holds if "always" means always — a client that stops sending the field once vacationInternalAvailable turns false leaves extended rules of its users in place instead of sunsetting them. On read, every vacation rule reports its vacationMode (all on classic notices too, pre-existing rules included) — sole exception are multi-branch rules the middleware does not recognize as extended vacation rules: they report no mode and carry an errormsg instead, see below; textExt/subjectExt are present exactly when set. Invalid combinations and values are rejected with MAIL_FILTER-0044: split without textExt, all/internalOnly combined with the external fields, an unknown mode value, external fields without vacationMode, and a subjectExt containing line breaks. A rule carrying more than one vacation action is rejected with the new MAIL_FILTER-0045.

Whether a sender is internal or external is decided by the classifier header the mail platform stamps on every delivered message (see the accompanying Configuration SCR). The feature is an operator opt-in; its availability is announced in the mail filter config action as vacationInternalAvailable, and requests introducing the extended modes while it is unavailable are rejected with MAIL_FILTER-0043. Updates of multi-branch rules the middleware does not recognize as extended vacation rules are rejected on both interfaces: the v2 interface refuses with MAIL_FILTER-0042 when the rule carries a vacation action and MAIL_FILTER-0041 otherwise (the legacy v1 interface makes a similar split, keyed on the rule's vacation flag), and the v2 list action announces the refusal up front by reporting such rules with an errormsg in the matching wording (the rule and its leading branch stay reported), so clients can render them read-only instead of failing on save. The v1 interface additionally rejects every extended vacation rule with MAIL_FILTER-0042, pointing the user to an up-to-date client (they stay fully editable through v2). See the accompanying Java-API SCR for the underlying parser change.

The pre-existing subject field now rejects line breaks the same way the new subjectExt does (MAIL_FILTER-0044): a line break used to be written verbatim into the Subject: header of the generated reply — saves that used to pass with a multi-line subject now fail.

Known limitation: Exchange ActiveSync devices read and set the out-of-office state through the legacy v1 interface (USM), whose vacation model cannot represent the extended two-branch structure — for a split/internalOnly notice such a device shows OOF as switched off, and setting OOF from the device fails. Editing the notice through the v2 interface is unaffected.

Existing clients are otherwise unaffected: without the new fields the produced Sieve rule is unchanged, and the additions to the JSON returned on read are the vacationMode field (all) on every vacation rule and the errormsg on unrecognized multi-branch rules. See the feature documentation for further details.

SCR-1875

Summary: New optional parameter applyDefaultAlarms for the iCal import request

Effective: 8.54.320 and later

The iCalendar import request import?action=ICAL accepts the new optional parameter applyDefaultAlarms. When set to true, alarms contained in the imported iCalendar data are skipped for appointments, and the calendar user's configured default alarms (defaultAlarmDate and defaultAlarmDateTime) are applied instead. It has no effect on tasks.

The appointment imported by the following request ends up with the user's default alarms, although the iCalendar data carries no VALARM component:

POST /ajax/import?action=ICAL&folder=cal%3A%2F%2F0%2F31&applyDefaultAlarms=true
Content-Type: multipart/form-data; boundary=--boundary

--boundary
Content-Disposition: form-data; name="file"; filename="appointment.ics"
Content-Type: text/calendar

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp//Booking//EN
BEGIN:VEVENT
UID:5a1c0f6e-3d21-4a77-9d1f-1e0b7c2a9f44
DTSTAMP:20260901T100000Z
DTSTART:20270301T100000Z
DTEND:20270301T110000Z
SUMMARY:Flight to Berlin
END:VEVENT
END:VCALENDAR
--boundary--

This addresses appointments that do not originate from the user's own calendar, e.g. one added from a mail attachment: such data usually carries either no alarm at all or an alarm chosen by whoever created the file, so the user ends up without the reminders they configured. Since the server cannot tell where the data came from, the client decides. The change is purely additive - without the parameter, alarms are imported as before, which keeps export/import round trips within the calendar module intact.

See the import request documentation for further details.

SCR-1874

Summary: Moved the user field guest_created_by from column 616 to column 627

Effective: 8.54.320 and later

The user module exposed the field guest_created_by as column 616, the very same identifier the contacts module uses for yomiFirstName. The user field has been moved to the previously unused column 627, so column 616 now denotes yomiFirstName in every module.

This is not backward compatible. Clients that request column 616 from user?action=all, user?action=list or user?action=search no longer receive guest_created_by but the contact's yomiFirstName; they have to request column 627 instead. The JSON field name guest_created_by is unchanged, hence user?action=get is not affected.

See the detailed user data for further details.

SCR-1860

Summary: New setting stating the trash folders of the OpenCloud/Nextcloud accounts of a user

Effective: 8.54.320 and later

The trash folder of every OpenCloud or Nextcloud account of the user is stated by the setting modules/files/opencloud/folder/trash or modules/files/nextcloud/folder/trash of the config tree, so io.ox/files//opencloud/folder/trash or io.ox/files//nextcloud/folder/trash as a JSLob path. For OpenCloud that folder is a virtual one holding the trash bins of the spaces, so it cannot be derived from the identifier of an account by a client. For Nextcloud it is the user’s trash bin the instance states.

The value is an object holding one fully qualified folder identifier per account, by the identifier of that account. It is empty for a user without an OpenCloud or Nextcloud account, and the setting is not available at all for a user without the infostore module.

{"1":"opencloud://1/L3RyYXNo"}
{"2":"nextcloud://2/L3JlbW90ZS5waHAvZGF2L3RyYXNoYmluL2FudG9uQGNvbnRleHQxLm94LnRlc3QvdHJhc2gv"}

SCR-1858

Summary: New actions and columns for the shares of items within external file storages

Effective: 8.54.320 and later

The shares an item has within an external file storage that supports being shared that way are stated and managed through the infostore module.

  • PUT /infostore?action=createShare creates a share, GET /infostore?action=listShares lists them, PUT /infostore?action=updateShare updates one, and PUT /infostore?action=removeShare removes them. The parameter id is optional for all of them: stated, it denotes the file to share, omitted, the folder the parameter folder states is shared.
  • The column 7050 of the detailed infoitem data and the column 3250 of the detailed folder data state the shares of an item, each of them as an object holding the properties of one share.

Purely additive — existing requests are unaffected.

See the API documentation for further details.

API - Java

SCR-1880

Summary: Changed behavior of Sieve script parsing: "elsif"/"else" control blocks become branches of a single rule instead of unsupported rules

Effective: 8.54.320 and later

The mail filter middleware now parses Sieve rules containing elsif/else control blocks into a single rule holding all branches; previously every such block was reported as a separate unsupported rule. The change applies to every parsed script — hand-written rules included — regardless of the feature toggle of the accompanying Configuration SCR.

Implementations of the com.openexchange.mailfilter.MailFilterInterceptor Java interface see these rules on every read and write and must not assume single-branch rules any more: a Rule may now carry several branches (IfCommand followed by ElsifCommand/ElseCommand entries), more than one vacation action, and an else branch without a test command. The new Rule.getBranches() method enumerates a rule's branches; Rule.hasMultipleBranches() names the multi-branch check. Both are documented on Rule and MailFilterInterceptor. Deployments without own interceptor implementations are unaffected.

Consequences for scripts containing such blocks:

  • their commands now participate in the Sieve capability validation and contribute to the regenerated require line on every write; a command requiring a capability the Sieve server does not announce makes the write fail (previously such blocks were preserved verbatim and ignored by the validation)

  • a script write-back regenerates the blocks in canonical formatting instead of copying them verbatim — comments and custom formatting inside hand-written elsif/else blocks are lost on the next write through the middleware; note that saving any rule regenerates the whole script, so an edit of an unrelated rule already triggers this

  • rule listings shift: every such block used to occupy a list position of its own as an "unsupported" error rule; it now merges into its preceding rule, so affected scripts list fewer rules and following rules move up (the merged error rules were not editable anyway)

Script parsing additionally normalizes lone CR characters (classic-Mac line breaks) to CRLF, inside string literals such as vacation texts too; a script containing lone CRs — e.g. written through ManageSieve — is persisted in the normalized form on its next write through the middleware.

API - REST

SCR-1986

Summary: New administrative REST endpoints for inspecting the cross-context grant index

Effective: 8.54.320 and later

Two preliminary endpoints under HTTP basic authentication report which foreign contexts hold cross-context access on a resource, as recorded in the xctx_grants index:

  • GET /preliminary/crosscontext/v1/grants/{context}/{entity} - for one resource owner, e.g. a shared account
  • GET /preliminary/crosscontext/v1/grants/{context} - for every resource owner of a context that has one
{"context": 1337, "entity": 14, "grants": {"SHARED_ACCOUNT": [42, 58]}}

The grants are keyed by type rather than by groupware module, because a grant can be module-less. Both endpoints report the index verbatim: no backing store is consulted, there is no fallback when the index holds nothing, and the trust-zone authority is not applied - so an empty result means nothing is recorded, not that nothing exists. Purely additive.

See the REST API documentation for further details.

SCR-1939

Summary: SCIM: query parameter deleteMode on DELETE /Users/{id} for an immediate hard delete

Effective: 8.54.320 and later

The SCIM endpoint accepts the query parameter deleteMode on DELETE /scim/v2/contexts/{cid}/Users/{id} with the values deactivate, softDelete and delete, overriding the mode configured through com.openexchange.scim.deleteMode for that call. With delete the account is removed at once even in a context configured for softDelete, and an account that is soft-deleted already (and therefore hidden from SCIM) is removed as well, bypassing the retention period: the way to honor a request under GDPR Art. 17 without waiting. An unknown value is answered with 400 invalidValue. Without the parameter nothing changes. OpenAPI document and documentation (administration/scim.md, section "Delete mode") updated.

SCR-1925

Summary: Soft-deleting and restoring users over the provisioning API

Effective: 8.54.320 and later

UserService.DeleteUsers takes the enum field mode (HARD, the default, or SOFT), the new RestoreUsers (POST /prov/v1/contexts/{context_id}/users:restore) lifts the soft-deleted state, and ListUserData lists the soft-deleted users of a context with the filter soft_deleted=true. The User message carries the read-only soft_deleted (milliseconds since the epoch), absent for every other user. Soft-deleting the context administrator, a guest or an already soft-deleted user, and restoring a user that is not soft-deleted, yield 400.

DeleteUsers with mode: SOFT now honors dest_user, which it accepted and ignored before: it names the user the shared data is reassigned to once the retention period has passed. Absent leaves it to the context administrator, 0 or less drops the data. A destination that does not exist, is a guest, is soft-deleted itself or is one of the users being soft-deleted yields 400.

SCR-1918

Summary: Added the /SharedAccounts, /Deputies and /SecondaryAccounts types to the SCIM 2.0 service provider

Effective: 8.54.320 and later

The SCIM 2.0 service provider ([SCR-1901], [SCR-1907], [SCR-1914]) now covers the shared accounts of a context: mailboxes and calendars several users work in, provisioned through OXSharedAccountInterface. It also covers deputies, provisioned through OXDeputyPermissionsInterface, and the secondary mail accounts of the users, provisioned through OXSecondaryAccountInterface.

  • New resource type SharedAccount under /scim/v2/contexts/{context_id}/SharedAccounts with the schema urn:ietf:params:scim:schemas:extension:openxchange:2.0:SharedAccount: the profile attributes of a user (userName, displayName, name, emails, preferredLanguage, timezone, phone numbers, addresses, the enterprise extension) without active and groups; password (write only, the mailbox password, random when omitted); aliases (the mailbox address is always part of it); permissions, one entry per user or group of the context with value, $ref, type (User or Group), mail and calendar as permission level none, viewer, editor, author or admin (absent for no access), grantedCapabilities and deniedCapabilities such as sendAs. GET with filter (eq on userName, displayName, emails.value, externalId, combinable with and), startIndex and count; POST, GET, PUT, PATCH, DELETE with the versioning of [SCR-1909]. userName and displayName are unique within the context (409 uniqueness). A listing leaves permissions out, since they cost a provisioning call per account; a single read carries them.
  • A PUT applies what the document carries and keeps the rest: the provisioning API converts a shared account to a user on its way to the storage and skips unset fields, so its attributes cannot be cleared. permissions omitted on PUT stay as they are; an empty list, or a PATCH removing the attribute, removes every permission granted within the context. Permissions are set per distinct access in one call; a permission naming a user or group that does not exist, or an unknown capability, is refused with 400 invalidValue, and on POST the just created account is removed again in that case. Permissions granted to users of other contexts are neither shown nor touched.
  • DELETE removes the account and its mailbox; a shared account cannot log in, so there is nothing to deactivate. externalId is stored with resource type 4 and removed with the account; shared accounts stay invisible under /Users.
  • Discovery: /ResourceTypes lists the SharedAccount, Deputy and SecondaryAccount types, /Schemas their schemas.
  • The photo, the full set of phone and fax types and the OX-specific contact fields of the user extension ([SCR-1908]) apply to the shared account as well.
  • New resource type Deputy under /scim/v2/contexts/{context_id}/Deputies with the schema urn:ietf:params:scim:schemas:extension:openxchange:2.0:Deputy: grantor (the user delegating, required and immutable; a different one is refused with 400 mutability), deputy (value, $ref, type User or Group; immutable as well), sendOnBehalfOf, folderMode (default, all, specific), classifiedAccess (none, confidential, private) and modules, one entry per module with permission as level none, viewer, editor, author or admin and, for specific, the folders. Addressed by the identifier the deputy service assigns; an externalId of the client's own system is stored and searchable. GET with filter (eq on grantor.value, deputy.value, deputy.type, externalId), POST, PUT, PATCH, DELETE; a PUT keeps what it does not carry, and "externalId": null removes the external identifier. A grant made outside the simple permission mode reads as custom and cannot be written back; granting a module to the same deputy twice is refused with 409 uniqueness. The module mail needs an administrative way into the grantor's mailbox - a token Dovecot accepts, the mail master account, or DoveAdm. No notification mail is sent.
  • New resource type SecondaryAccount under /scim/v2/contexts/{context_id}/SecondaryAccounts with the schema urn:ietf:params:scim:schemas:extension:openxchange:2.0:SecondaryAccount: one mail account of one user, addressed as {user}-{account}, which stays the same when the address changes. user (required and immutable), primaryAddress (required, unique among the accounts of its user), name (the address when omitted), personal, replyTo, login (required), password (write only), mail and transport with server, port, protocol, secure, startTls and, for transport, its own login and password; on POST a source (none, primary, localhost) for an end-point the document leaves out; the standard folders, the spamHandler and an externalId of the client's own system. GET with filter (eq on user.value, primaryAddress, externalId), POST, PUT, PATCH, DELETE; a PUT keeps what it does not carry, and "externalId": null removes the external identifier. A second account with the same address is refused with 409 uniqueness. Passwords are never returned.

Purely additive. /SharedAccounts requires com.openexchange.sharedaccount.enabled=true, as the provisioning API does.

SCR-1917

Summary: Completed the App Suite user extension of the SCIM 2.0 service provider: capabilities, clearing by null, driveUserFolderMode, filestoreId

Effective: 8.54.320 and later

The App Suite user extension urn:ietf:params:scim:schemas:extension:openxchange:2.0:User of the SCIM 2.0 service provider (SCR-1901) now covers the remaining per-user settings of the provisioning API.

  • New multi-valued string attribute capabilities: the per-user capability overrides as changecapabilities stores them, a name grants a capability, a leading minus denies one. Rendered on single reads only, never in listings. A list sent with PUT or PATCH becomes the stored set: names it adds are granted or denied, names it no longer carries are dropped so the configuration applies again; an omitted attribute keeps the stored overrides, an explicit null or a PATCH remove drops them all. A name the permission configuration forbids is refused with 400 invalidValue; on POST the just created account is removed again in that case. Both a name and its denial in one list are refused.
  • A null alias list, or a PATCH removing aliases, reduces the aliases to the mailbox and sender addresses. A null for, or a PATCH removing, imapLogin, imapServer, smtpServer, defaultSenderAddress, maxQuota, passwordExpired or accessCombinationName, which the provisioning API cannot clear, is refused with 400 and a message naming the value to send instead; previously it was ignored.
  • The version of a single read (meta.version, ETag) now covers the access combination and the capability overrides, so a conditional GET with If-None-Match notices their change instead of answering 304; If-Match on PUT, PATCH and DELETE is checked against that version. The version of a user in a listing still covers only what the listing shows. accessCombinationName and capabilities are declared returned: default in /Schemas.
  • New attribute driveUserFolderMode (default, normal, none, case-insensitive), the driveUserFolderMode of the provisioning create: honored on POST only, declared immutable and returned: never since the provisioning API does not store it; a PUT or PATCH carrying a value is refused with 400 mutability.
  • New integer attribute filestoreId, declared immutable: on POST the user gets an own file storage there, as with the provisioning create; on reads it is rendered while the user has an own storage. A PUT or PATCH may echo the stored value, any other value, and a null while a storage is set, is refused with 400 mutability, since moving a user's files is a job of the provisioning API.

Provisioning error messages that wrap an internal exception are reduced to the message; a missing file store and a quota the provisioning API may not assign are answered with 400 instead of 500. Users with an own file storage gain filestoreId in their representation, and every single read carries the access combination in its version, so versions change once. Everything else is additive; /Schemas lists the new attributes.

SCR-1914

Summary: Added the /Resources type and group memberships on users to the SCIM 2.0 service provider

Effective: 8.54.320 and later

The SCIM 2.0 service provider (SCR-1901, SCR-1907) now covers the resources of a context and shows memberships from both sides.

  • New resource type Resource under /scim/v2/contexts/{context_id}/Resources with the schema urn:ietf:params:scim:schemas:extension:openxchange:2.0:Resource: displayName and email are required, name is derived from the display name unless sent (lower-cased, blanks turned into dashes, accented letters reduced, a counter appended where taken), description, available (true by default) and permissions, a list of {value, type, privilege} where value is a user or group identifier, type is User or Group and privilege one of none, ask_to_book, book_directly, delegate. GET with filter (eq on name, displayName, email, externalId, combinable with and), startIndex and count; POST, GET, PUT, PATCH, DELETE with the versioning of SCR-1909. name and email are unique within the context (409 uniqueness), a name sent explicitly is checked against CHECK_RES_UID_REGEXP, permissions follow com.openexchange.resource.simplePermissionMode. Permissions omitted on PUT stay as they are; an empty list restores the default. externalId is stored with resource type 3 and removed with the resource.
  • Users carry the read-only groups attribute on single reads (value, $ref, display of every group the user is a member of; declared returned: request), groups carry members[].display on single reads. Listings leave both out, so meta.version agrees between a listing and a single read.
  • Discovery: /ResourceTypes lists the Resource type, /Schemas its schema.

Purely additive. Attributes declared returned: request are rendered only when the attributes parameter of a single read names them.

SCR-1910

Summary: Added JSON Web Tokens as bearer credential to the SCIM 2.0 service provider

Effective: 8.54.320 and later

The SCIM 2.0 service provider (SCR-1901) now accepts a JSON Web Token issued by the identity provider as Bearer credential next to provisioning tokens, once com.openexchange.scim.allowJwt is enabled for the context. A bearer value containing a dot is treated as JWT; provisioning tokens never contain one.

  • The token is validated by the OAuth provider in mode expect_jwt (signature against the configured JWK set, issuer, audience, expiry) and resolved to a context and a user through the provider's claim lookup (contextLookupClaim, userLookupClaim). It has to resolve to the context in the URL, its subject has to be the context administrator, and its scope has to carry scim (mapped through com.openexchange.oauth.provider.scope.[EXTERNAL_SCOPE]). Requests made with it act as the context administrator, like provisioning tokens.
  • A valid token for another user or without the scope is answered with 403; an invalid, expired or foreign token with 401; 503 while the provider cannot reach its key source or no OAuth authorization service is available. Refusals are logged with the client (azp) and the reason, and never counted against the lock for failed basic authentications.
  • /ServiceProviderConfig lists the scheme JSON Web Token once it is enabled.

Purely additive; nothing changes while the property stays at its default.

SCR-1909

Summary: Added resource versions with If-Match and read-only checks to the SCIM 2.0 service provider

Effective: 8.54.320 and later

The SCIM 2.0 service provider (SCR-1901, SCR-1907) now versions its resources (RFC 7644, section 3.14) and refuses PATCH operations on read-only attributes.

  • Every user and group carries meta.version, a weak entity tag derived from the attributes of its representation, and is returned with the ETag header on single reads, POST, PUT and PATCH; /ServiceProviderConfig advertises etag.supported=true. The version is the same on every node and does not depend on the request's host.
  • PUT, PATCH and DELETE /Users/{id} and /Groups/{id} honor If-Match (entity tags or *, weak comparison): a resource that changed since the client read it is answered with 412 and nothing is written. If-None-Match on a single read yields 304. Without these headers the behavior is unchanged, the last writer wins.

  • A PATCH operation whose path targets a read-only attribute (id, meta, groups) is refused with 400 mutability instead of being applied and silently dropped. Read-only attributes inside a path-less value, as echoed back by some providers, are ignored the way PUT ignores them.

Purely additive for clients that do not send the headers.

SCR-1908

Summary: Added the App Suite user extension to the SCIM 2.0 service provider

Effective: 8.54.320 and later

Settings a directory does not model, but an operator wants to drive per user, are now available on /scim/v2/contexts/{context_id}/Users in the extension urn:ietf:params:scim:schemas:extension:openxchange:2.0:User, declared in /Schemas and listed for the User resource type. Unlike the core attributes, an extension attribute the document omits on PUT keeps its value; only what is sent changes.

  • accessCombinationName: the named module access combination from ModuleAccessDefinitions.properties, applied on create and changed through the provisioning API on update. An unknown name is refused with 400. Declared returned: request and returned on single reads only.
  • aliases: the alias set. The mailbox address and the default sender address are always part of it, as the provisioning API insists on; when the mailbox address changes, the old one is dropped.
  • defaultSenderAddress: added to the aliases where missing; a sender equal to the mailbox address follows it when that changes.
  • maxQuota in megabytes (-1 for unlimited), imapLogin, imapServer, smtpServer and passwordExpired.
  • The OX-specific personal and company contact fields that have no home in the core or enterprise schema: birthday and anniversary as ISO dates, maritalStatus, numberOfChildren, spouseName, profession, roomNumber, assistantName, note, info, categories, businessCategory, commercialRegister, taxId, salesVolume, and the 20 free-form fields as the positional array userFields. Like the other extension attributes they are cleared by an explicit null.

For the context administrator, mail servers and password state cannot be changed over SCIM (403), in addition to password, deactivation and deletion: pointing the administrator's mail account at another host would hand that password over. Purely additive.

SCR-1907

Summary: Added the /Groups endpoint to the SCIM 2.0 service provider

Effective: 8.54.320 and later

The SCIM 2.0 service provider (SCR-1901) now serves the groups of a context under /scim/v2/contexts/{context_id}/Groups, so an identity provider can provision group memberships next to the users. Authentication, media types, body limits and error model are those of the users endpoint.

  • GET /Groups with filter (eq on displayName, externalId and the App Suite name, combinable with and), startIndex and count; GET /Groups/{id}. Members are rendered with value, $ref and type.
  • POST /Groups: displayName is required and unique within the context (409 uniqueness otherwise). The identifier the provisioning API needs besides lives in the extension urn:ietf:params:scim:schemas:extension:openxchange:2.0:Group as name; when a client does not send it, it is derived from the display name (lower-cased, blanks turned into dashes, accented letters reduced to their base letter, a counter appended where the name is taken). A name sent explicitly is checked against CHECK_GROUP_UID_REGEXP.
  • PUT /Groups/{id} replaces display name and members; a document without members empties the group. PATCH /Groups/{id} applies add with a list of members, remove with members[value eq "..."] or with the members named in value, and replace of displayName; adding a member twice is harmless. DELETE /Groups/{id} removes the group.
  • Only regular users can be members; a member referring to a guest or an unknown user is refused with 400 invalidValue. The context's standard group is readable but refuses changes and deletion with 403.
  • externalId is stored in scim_external_id with resource type 2 and searchable. /ResourceTypes lists the Group type and /Schemas the core group schema and the extension.

Purely additive. See the administration article "SCIM provisioning" for the mapping and the identity provider setup.

SCR-1901

Summary: Added a SCIM 2.0 service provider for provisioning the users of a context from an identity provider

Effective: 8.54.320 and later

In order to let an identity provider such as Entra ID, Okta, authentik or the Univention Nubus provisioning client drive the users of a context with the SCIM connector it already ships, the middleware now acts as a SCIM 2.0 service provider (RFC 7643, RFC 7644). The context is the SCIM tenant and sits in the base URL /scim/v2/contexts/{context_id}; the endpoint is served by the new package open-xchange-scim on the admin role and is meant to be routed to a public hostname for exactly the /scim/ prefix.

  • GET /ServiceProviderConfig, GET /ResourceTypes and GET /Schemas: discovery, declaring the supported subset of the core user schema and the enterprise extension.
  • GET /Users with filter (eq on userName, externalId, emails.value and displayName, combinable with and), startIndex and count (at most 200); other filters are refused with invalidFilter.
  • POST /Users, GET, PUT, PATCH and DELETE /Users/{id}: PATCH follows RFC 7644 including paths such as emails[type eq "work"].value and the string booleans Entra ID sends for active; attribute names are matched case-insensitively and unknown ones are refused with invalidPath. externalId is stored and searchable. active maps to mailenabled. A user created without password gets a random, unusable one and logs in through single sign-on.
  • DELETE deactivates by default; see SCR-1902 for com.openexchange.scim.deleteMode.
  • The mapped core attributes cover the full contact record: photos carried as a base64 data: URI, and phoneNumbers for every phone and fax slot the user has (work, work2, home, home2, mobile, mobile2, fax, fax_home, fax_other, pager, other, assistant, callback, car, company, ip, isdn, primary, radio, telex, ttytdd), alongside the name, e-mail, instant-messaging and postal-address attributes and the enterprise extension.

Callers authenticate with a Bearer provisioning token of scope SCIM bound to the context (SCR-1897), which acts as the context administrator, or with HTTP basic credentials checked like every provisioning operation. The endpoint never grants access without a credential, refuses basic credentials while administrator authentication is disabled in the deployment, and locks a login for fifteen minutes after ten failed basic attempts, answered with 429. Only regular accounts are visible; the context administrator cannot be deactivated, deleted or given a password over SCIM. Request bodies are limited to one megabyte. Responses use application/scim+json; application/json is accepted in Accept and Content-Type. Purely additive. See the administration article "SCIM provisioning" for the attribute mapping and the identity provider setup.

SCR-1897

Summary: Added provisioning tokens as bearer credentials for scoped provisioning interfaces

Effective: 8.54.320 and later

In order to let automated clients such as an identity provider or a provisioning script authenticate without an administrator's password, the provisioning API gains provisioning tokens: bearer secrets bound to one scope and to one context or, as cross-context tokens, to several contexts at once, managed by the new gRPC service ProvisioningTokenService, which the HTTP gateway exposes by default.

  • POST /prov/v1/contexts/{context_id}/tokens creates a token from label, scope (SCIM or PROVISIONING) and an optional expires in milliseconds since the epoch (0 or absent: the token does not expire). The response carries the metadata and, exactly once, the secret of the form ox_<context-id>_<64 hex characters>.
  • GET /prov/v1/contexts/{context_id}/tokens lists the tokens of a context without secrets, including lastUsed and, in contextIds, the contexts a token opens.
  • DELETE /prov/v1/contexts/{context_id}/tokens/{token_id} revokes a token.
  • POST /prov/v1/tokens creates a cross-context token from contextIds (at least two distinct contexts), label, scope and expires; its secret has the form ox_x_<64 hex characters>. GET /prov/v1/tokens lists the cross-context tokens the caller stands above, DELETE /prov/v1/tokens/{token_id} revokes one.
  • GET /prov/v1/contexts/{context_id}/cross-context-tokens lists the cross-context tokens that open a context, for the administrator of that context, each naming that context and no other; DELETE /prov/v1/contexts/{context_id}/cross-context-tokens/{token_id} ends that one context's exposure without touching the others.

The tokens of a context are managed like every other operation inside a context: by the context administrator, a reseller administrator owning the context or, where MASTER_ACCOUNT_OVERRIDE permits it, the master administrator. Cross-context tokens are managed only by the master administrator or a reseller administrator owning every one of the contexts; creating one additionally needs MASTER_ACCOUNT_OVERRIDE: with the override off no administrator reaches into a context, so none may issue a token that acts inside one, while listing and revoking work regardless, so what was issued before can still be seen and taken back. A cross-context token is issued above the contexts, so the context it opens has no part in it; its administrator can however see which cross-context tokens reach into the context and detach the context from one, which ends that exposure without revoking the token and is no lasting veto. They are stored in the configuration database, and a context that is deleted is dropped from them; a token left without a context is deleted with it. Only the SHA-256 hash of a secret is stored.

A token of scope SCIM opens the SCIM service provider of each context it is bound to. A token of scope PROVISIONING is presented on /prov as Authorization: Bearer <secret> and acts as an administrator of exactly the contexts it is bound to: any other context, every master operation such as creating a context, and the token services themselves are refused with 401. A cross-context token of that scope is what lets one credential grant shared account permissions across contexts.

The new bundles com.openexchange.provisioning.token and com.openexchange.provisioning.token.impl ship with open-xchange-core; the service com.openexchange.grpc.provisioning.ProvisioningTokenService is part of the gateway's default provisioningGateway.services list. Purely additive, existing operations are unaffected.

SCR-1861

Summary: New REST end-point POST /authentication/v1/resolve to resolve a user to its identifiers

Effective: 8.54.320 and later

In order to let an external authentication service look up a user before a session exists, the new end-point POST /authentication/v1/resolve resolves a user to its user identifier, context identifier and the database schema its context lives in. It is protected by Basic authentication like the other end-points of that bundle.

The request body denotes the user in exactly one of two shapes:

  • loginInfo with contextName and userName - the caller has already mapped its identity provider's response onto the login names, which are looked up as-is.

  • identity with type and value - an opaque identifier the caller cannot map itself, left to a deployment-specific resolver.

A body that sets both or neither is answered with 400, a user no resolver knows with 404.

The resolution itself is provided by implementations of the new OSGi service com.openexchange.external.authentication.common.api.identity.UserResolver, exported by bundle com.openexchange.external.authentication.common. They are consulted in the order of their service ranking; the built-in resolver has the lowest possible ranking and handles the loginInfo shape only, so a deployment can contribute its own resolver for opaque identifiers without displacing it.

API - RMI

SCR-1943

Summary: New RMI interface OXProvisioningTokenInterface

Effective: 8.54.320 and later

The new RMI interface com.openexchange.admin.rmi.OXProvisioningTokenInterface, bound as OXProvisioningToken, manages provisioning tokens, as the gRPC service ProvisioningTokenService does. For the tokens of a context, create(Context, String label, String scope, long expires, Credentials) returns the new token together with its secret, list(Context, Credentials) the tokens of the context without secrets, and revoke(Context, String tokenId, Credentials) whether a token was revoked. For cross-context tokens, which open several contexts at once, createCrossContext(Context[] ctxs, String label, String scope, long expires, Credentials) takes at least two distinct contexts and the credentials of the master administrator or a reseller administrator owning every one of the contexts, and only where MASTER_ACCOUNT_OVERRIDE lets an administrator reach into a context at all, listCrossContext(Credentials) returns the cross-context tokens the caller stands above, which needs no override for the master administrator, and revokeCrossContext(String tokenId, Credentials) whether one was revoked; a context administrator is refused on all three. The context reached into is not left without a say: listCrossContextReachingInto(Context, Credentials) returns the cross-context tokens that open the given context, each naming that context and no other, and detachCrossContext(Context, String tokenId, Credentials) ends that one context's exposure - the token keeps working for every other context it opens and is deleted only if this was the last one. Both are authenticated against the context reached into, so its own administrator may call them; neither is a revocation nor a lasting veto. Tokens travel as the serializable data object com.openexchange.admin.rmi.dataobjects.ProvisioningToken, whose secret is set only on the result of a create; getContextIds() names the contexts a token opens, and a cross-context token has getContextId() 0 and isCrossContext() true. The context's schema is brought up to date first, and invalid input such as an unknown scope, an expiration time in the past or a single context for a cross-context token is refused with InvalidDataException. The interface is registered by com.openexchange.admin and is not site-aware. Purely additive.

SCR-1923

Summary: Soft-deleting and restoring users over OXUserInterface

Effective: 8.54.320 and later

OXUserInterface offers softDelete(Context, User[], Credentials), restore(Context, User[], Credentials), both also for a single user, and listSoftDeleted(Context, Credentials). A soft-deleted user is a leaver: hidden from the address book, not invitable, unable to log in, deleted for good after the retention period, while the data is kept and the login name stays reserved (see the behavioral change). The context administrator, guests, shared accounts and users that are already soft-deleted are rejected with InvalidDataException, as is restoring a user that is not soft-deleted. The data object User carries the read-only softDeleted (java.util.Date), null for every other user; the listing returns identifier and softDeleted only.

softDelete is also offered as softDelete(Context, User[], Integer, Credentials) and for a single user, where the Integer names the user the shared data is reassigned to once the retention period has passed, with the same meaning as destUser on delete: null leaves it to the context administrator, 0 or less drops the data. The destination is checked when it is named - it must exist and may be neither a guest, nor the user being soft-deleted, nor a soft-deleted user itself (InvalidDataException) - and checked again before it is used. restore forgets it.

SCR-1889

Summary: New Field classifiedAccess in the Deputy Permission Data Objects of the Administrative RMI and gRPC Interfaces

Effective: 8.54.320 and later

The data objects com.openexchange.admin.rmi.dataobjects.DeputyPermission (and thereby ActiveDeputyPermission) and DeputyPermissionDescription used by OXDeputyPermissionsInterface gained the field classifiedAccess next to sendOnBehalfOf, with the accessors getClassifiedAccess() and setClassifiedAccess(String) (plus isClassifiedAccessSet() / removeClassifiedAccess() on the description). It carries the level of the granting user's classified appointments a deputy may see with all details in the covered calendar folders: none or confidential, null when not granted; appointments marked as private always stay hidden from deputies, and the attribute has no meaning for other modules. The gRPC provisioning interface exposes the same as field classified_access (number 7) of the DeputyPermission message and as classifiedAccess / ClassifiedAccessSet (numbers 13 and 14) of the DeputyPermissionDescription message in deputy.proto. A value other than none or confidential is rejected with an InvalidDataException; null still means none when granting, and an attribute not set on the description leaves the level unchanged when updating.

Purely additive - the serialVersionUIDs of the data objects are unchanged, so RMI clients built against the previous version keep working, and the proto fields are wire compatible. See the feature documentation for further details.

API - SOAP

SCR-1950

Summary: New SOAP service OXProvisioningTokenService

Effective: 8.54.320 and later

The new SOAP service OXProvisioningTokenService manages provisioning tokens, the bearer secrets an automated client such as an identity provider driving the SCIM service provider or a script driving the provisioning API authenticates with, and offers what the command line tools createprovisioningtoken, listprovisioningtokens and revokeprovisioningtoken do. create takes the context, a label of at most 128 characters, the scope (scim or provisioning) and an optional expires in milliseconds since the epoch (0 or absent: no expiry) and returns the token with its secret, the only time the secret is shown; list returns the tokens of the context with their lastUsed time but without secrets; revoke takes the tokenId and returns true if the token existed. For cross-context tokens, which open several contexts at once, createCrossContext takes the contexts as ctxs (at least two distinct ones) with label, scope and expires, listCrossContext returns the cross-context tokens the caller stands above, and revokeCrossContext takes the tokenId; creating needs the master administrator or a reseller administrator owning every one of the contexts, and only where MASTER_ACCOUNT_OVERRIDE lets an administrator reach into a context at all, listing and revoking the master administrator or, where MASTER_ACCOUNT_OVERRIDE permits it, a reseller administrator owning every one of the contexts. For the context reached into, listCrossContextReachingInto takes the context and returns the cross-context tokens that open it, each naming that context and no other, and detachCrossContext takes the context and a tokenId and ends that one context's exposure; both are authenticated against that context, so its own administrator may call them. The ProvisioningToken element carries the contexts a token opens in contextIds; a cross-context token has contextId 0. Authorization for a context follows every other operation inside a context: the context administrator, a reseller administrator owning the context or, where MASTER_ACCOUNT_OVERRIDE permits it, the master administrator. The service ships with open-xchange-admin-soap; its WSDL is at /webservices/OXProvisioningTokenService?wsdl. Example request and response, and a cross-context request:

<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:create>
      <soap:ctx>
        <xsd:id>1</xsd:id>
      </soap:ctx>
      <soap:label>Entra ID</soap:label>
      <soap:scope>scim</soap:scope>
      <soap:auth>
        <xsd1:login>oxadmin</xsd1:login>
        <xsd1:password>secret</xsd1:password>
      </soap:auth>
    </soap:create>
  </soapenv:Body>
</soapenv:Envelope>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <ns2:createResponse xmlns="http://dataobjects.soap.admin.openexchange.com/xsd" xmlns:ns2="http://soap.admin.openexchange.com">
      <ns2:return>
        <id>5b0e7c2a9d4f4e1b8c3a6d9f2e1b4c7a</id>
        <contextId>1</contextId>
        <contextIds>1</contextIds>
        <label>Entra ID</label>
        <scope>scim</scope>
        <createdBy>oxadmin</createdBy>
        <created>1789112149008</created>
        <expires>0</expires>
        <lastUsed>0</lastUsed>
        <secret>ox_1_9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08</secret>
      </ns2:return>
    </ns2:createResponse>
  </soap:Body>
</soap:Envelope>
<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:createCrossContext>
      <soap:ctxs>
        <xsd:id>1</xsd:id>
      </soap:ctxs>
      <soap:ctxs>
        <xsd:id>2</xsd:id>
      </soap:ctxs>
      <soap:label>Shared account automation</soap:label>
      <soap:scope>provisioning</soap:scope>
      <soap:auth>
        <xsd1:login>oxadminmaster</xsd1:login>
        <xsd1:password>secret</xsd1:password>
      </soap:auth>
    </soap:createCrossContext>
  </soapenv:Body>
</soapenv:Envelope>

SCR-1924

Summary: Soft-deleting and restoring users over the OXUserService SOAP interface

Effective: 8.54.320 and later

The OXUserService offers the operations softDelete, softDeleteMultiple, restore, restoreMultiple and listSoftDeleted, the SOAP counterparts of the new OXUserInterface methods. The User element carries the read-only soft_deleted (xs:dateTime), absent for a user that is not soft-deleted. Clients that generate their stubs from the WSDL regenerate them to use the operations; existing operations are unchanged.

softDelete and softDeleteMultiple take the optional element reassign, the user the shared data is reassigned to once the retention period has passed, with the same meaning as on delete.

SCR-1921

Summary: Administrative SOAP operations accept a plain contextId, and moveContextFilestore reports the correct fault

Effective: 8.54.320 and later

Several administrative SOAP operations now accept the context identifier directly, as an alternative to sending a whole ctx element. The new contextId element is optional and appended after the existing ones, so requests that do not use it are unaffected. When both are given, contextId wins.

Affected operations:

  • OXTaskMgmtService: flush, deleteJob, getJobList, getTaskResults
  • OXGroupService: listAll

A request may now be sent as:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:s="http://soap.admin.openexchange.com"
                  xmlns:r="http://dataobjects.rmi.admin.openexchange.com/xsd">
  <soapenv:Body>
    <s:listAll>
      <s:auth>
        <r:login>oxadmin</r:login>
        <r:password>secret</r:password>
      </s:auth>
      <s:contextId>1</s:contextId>
    </s:listAll>
  </soapenv:Body>
</soapenv:Envelope>

Existing clients are unaffected on the wire: the element is minOccurs="0" and the previous element order is unchanged. Clients that compile against the generated Java stubs of getJobList, getTaskResults or listAll see one additional parameter after regenerating them.

Independently of that, OXContextService.moveContextFilestore reported a NoSuchReasonException fault when the destination filestore did not exist, although the operation declares NoSuchFilestoreException for exactly that case. It now reports the declared fault. The WSDL is unchanged; only which of the two declared faults is returned differs.

SCR-1888

Summary: New Element classifiedAccess in the Deputy Permissions of the OXDeputyPermissionsService

Effective: 8.54.320 and later

The DeputyPermission and ActiveDeputyPermission types of the OXDeputyPermissionsService SOAP interface gained the optional element classifiedAccess, next to sendOnBehalfOf. It lets the granting user allow the deputy to see appointments marked as confidential in the covered calendar folders with all details, independently of the deputy attending them; like sendOnBehalfOf it is an attribute of the whole deputy permission, but it exclusively concerns the calendar. Accepted values are none (default) and confidential (confidential appointments are shown with details); appointments marked as private always stay hidden from deputies. The element is honored by grant and update (where it is only applied when present, so none revokes the right), and returned by list and getDeputyPermission; it is absent when the right was not granted. A level that cannot be granted fails with DEPUTY-0014. A value other than none or confidential is rejected as invalid data; an absent value still means none when granting and leaves the level unchanged when updating.

Example grant request appointing user 7 as calendar deputy of user 4 with access to confidential appointments:

<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:sendOnBehalfOf>false</xsd:sendOnBehalfOf>
        <xsd:classifiedAccess>confidential</xsd:classifiedAccess>
        <xsd:modulePermissions>
          <xsd:moduleId>calendar</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>

A list response carries the element next to sendOnBehalfOf the same way:

<ActiveDeputyPermission>
  <userId>7</userId>
  <sendOnBehalfOf>false</sendOnBehalfOf>
  <classifiedAccess>confidential</classifiedAccess>
  <modulePermissions>
    <moduleId>calendar</moduleId>
    <folderIds>cal://0/31</folderIds>
    ...
  </modulePermissions>
  <deputyId>...</deputyId>
  <grantorId>4</grantorId>
</ActiveDeputyPermission>

Purely additive - a request without the element grants a permission exactly as before, and clients generated from the previous WSDL keep working. See the feature documentation for further details.

Behavioral Changes

SCR-2006

Summary: Reject Own-Object Rights in Cross-Context Folder Permissions

Effective: 8.54.320 and later

A cross-context grant on a calendar or contacts folder may no longer carry an own-objects level for reading, writing or deleting. Creating or updating a folder permission like that is refused with FLD-1039 (INVALID_PERMISSIONS).

A principal from another context never owns objects in the folder's context, so such a level granted nothing at object level. The grantee saw an empty folder, or could create appointments they could then neither change nor delete. All-objects levels, and own-objects levels for users of the folder's own context, are unaffected. The rule applies to cross-context deputy permissions as well.

Grants stored before this change remain in place, and a folder carrying one stays editable: only new or changed entries are checked. No operator action is required.

See the feature documentation for further details.

SCR-2001

Summary: Stricter anti-virus verdicts, more scanned downloads and a scan log

Effective: 8.54.320 and later

Anti-virus scanning fails closed in more cases: an ICAP answer carrying X-Infection-Found, X-Virus-ID or X-Violations-Found counts as infected, and an answer that is neither a finding nor an unmodified response, e.g. a redirect, counts as not scanned instead of clean. Whole mails (.eml, zip_messages, attach_src, get_structure) and zip downloads of PIM and appointment attachments are now scanned as well, and so are files downloaded via share links, which were not scanned before. An encrypted item downloaded via the drive module without decryption is logged as not scanned instead of being reported as clean. Users for whom scanning is enforced get the capability antivirus_enforced. Every scan outcome is logged by com.openexchange.antivirus.scan (findings and refused items at WARN) and counted in appsuite.antivirus.scans.outcome. No admin action; route that logger to your monitoring to review findings.

SCR-1985

Summary: Changed behavior of listing the permission holders of a shared account

Effective: 8.54.320 and later

listSharedAccountPermissionsForSharedAccount (SOAP and RMI, and the listsharedaccountpermissionsbysharedaccount command-line tool) now reports the permissions held by users and groups of every context, not only those that happen to reside in the same database schema as the shared account.

A cross-context permission is stored in the context it was granted to, so querying the account's own schema was always a partial answer whose completeness depended on how contexts were distributed across schemas. The contexts to read are now taken from the xctx_grants index.

No client change is required. On a system upgraded from an earlier version the index is backfilled by a daily job that skips schemas with a pending update task, so until those updates have run the previous, co-located-only result may still be returned.

SCR-1984

Summary: A Nextcloud account whose credentials the instance rejects states an error

Effective: 8.54.320 and later

An account whose credentials a Nextcloud instance rejects is put into an error state rather than having every request of it fail against the instance anew. The rejection is stored with the account, its folders state it towards the client, and it is logged once rather than per request. Throughout the period com.openexchange.file.storage.nextcloud.retryAfterErrorInterval states, see https://jira.atlassian.open-xchange.com/browse/SCR-1971 , the instance is not asked again; afterwards, the next request asks it once more and the error is forgotten if the credentials are accepted. Reconfiguring the account, e.g. by storing a new password or by linking another OAuth account, drops the error immediately, so a corrected account is usable without waiting. Only rejected credentials are remembered this way, any other failure being one of a single request.

SCR-1983

Summary: The Nextcloud file storage supports OAuth, versions, trash, sharing and search

Effective: 8.54.320 and later

The file storage service nextcloud was limited to reading and writing the files of an instance. It supports the following from now on, as far as the instance states that it does:

  • An account may be linked to an OAuth account rather than storing a username and an app token, see https://jira.atlassian.open-xchange.com/browse/SCR-1981 .

  • The versions of a file are listed, read, restored and removed.

  • A deleted item is listed within the trash bin of the account, restored to the location it was deleted from, and purged. It is restored by the instance, so it keeps its versions, and the location it was deleted from is fallen back to the folder a request states if it no longer exists.

  • An item is shared through a link, and the shares granted to the users and the groups of the instance are stated as the permissions of that item and applied from the ones a client states, see SCR-1971. The shared items are listed within virtual folders, see https://jira.atlassian.open-xchange.com/browse/SCR-1982

  • .

  • A search is performed by the instance, which evaluates the name and the media type of an item, while a criterion it does not evaluate is applied by the middleware to the items it states.

  • An item states the link that opens it within the web interface of the instance, and a preview of it is served as its thumbnail, which the instance serves under an endpoint of its own.

See the feature documentation for further details.

SCR-1973

Summary: Custom trust store is now honoured alongside the JVM's default trust store

Effective: 8.54.320 and later

A certificate that only the custom trust store knew was rejected whenever the JVM's default trust store was enabled as well, which is the default. Both stores were served by one trust manager each, and SSLContext only ever uses the first trust manager it is given, so the custom one was never asked. Setting com.openexchange.net.ssl.custom.truststore.enabled to true therefore had no effect unless com.openexchange.net.ssl.default.truststore.enabled was set to false, which in turn dropped every publicly known certificate authority.

Both trust stores are now served by a single trust manager that accepts a certificate as soon as either of them validates it. A certificate issued by an internal certificate authority is trusted while the public ones keep working.

This affects every outbound TLS connection of the middleware that runs with com.openexchange.net.ssl.trustlevel set to restricted; with the default all no certificate is validated in the first place and nothing changes. No configuration change is required. Deployments that worked around the defect by disabling the default trust store can enable it again.

SCR-1972

Summary: An over-sized MCP request body is refused with a JSON-RPC error instead of an empty 413

Effective: 8.54.320 and later

A request body above the MCP endpoint's limit of 1 MiB is answered with a JSON-RPC error object carrying -32700 and a message naming the limit, instead of a bare 413 with no content. A client that speaks only the protocol now learns why it was refused.

The answer is the same whichever way the size becomes known. A body whose Content-Length already exceeds the limit is refused before anything is read; one that never announced its length is refused while it is read. Until now only the second case could answer at all, and it did so differently.

Behind it, the body is parsed straight from a bounded reader rather than collected into a string first, so a request no longer holds its own body twice in memory while it is parsed. No admin action, no configuration.

SCR-1970

Summary: New folder type for the virtual folders of a file storage

Effective: 8.54.320 and later

A file storage may state folders that have no counterpart within it, but list the items of other folders under a certain aspect, such as the ones a user shares. Those folders are meant to be navigated to by a client, while a traversal of the folder tree is supposed to pass them over.

FileStorageFolderType states a value VIRTUAL_FOLDER for them now, which a storage sets on such a folder, and the ZIP archive of a folder passes them over along with the trash folder of the storage. The value is added to an existing enumeration. No storage stated folders of that kind before, so the archives of the existing storages are unchanged except for the Nextcloud one, whose virtual folders are passed over from now on rather than being archived along with the folders their items are located in.

SCR-1965

Summary: Drive offers the OAuth scope read_files

Effective: 8.54.320 and later

The Drive module now offers the OAuth scope read_files, so a user may grant an application read access to their files alone. Its read actions have carried @RestrictedAction(module = "files", type = READ) all along, but no bundle registered the scope with the OAuth provider, so it appeared on no consent screen and could not be granted - the module was out of reach for every token and every OAuth client. It is registered now the way every other module registers its scopes, by com.openexchange.file.storage.json, and requires the capability infostore. Like every module scope it opens the module, not a single feature: a token carrying read_files reads Drive through the HTTP API as well as through the read-only tools of the MCP endpoint (SCR-1945), which is what makes those tools usable in the first place. There is no write_files: writing to Drive stays outside what a scope can grant. No admin action.

SCR-1964

Summary: Cross-Context Shared Account Permissions Are Subject to the Cross-Context Trust Zones

Effective: 8.54.320 and later

A shared account permission for users or groups of another context is now subject to the cross-context trust zones: the shared account and the target context have to share at least one tag of com.openexchange.crosscontext.trustZones, otherwise the grant is refused with SAC-0008, reported as 403 over the HTTP provisioning gateway. There is no separate switch.

A caller that holds authority over the target context anyway is exempt. The policy is skipped whenever the credential in effect for that context - the one supplied for the entry if there is one, the credential of the call otherwise - authenticates against it. That covers an administrator credential valid in both contexts, as well as a scoped provisioning token that covers the target context.

The policy is evaluated when access is newly granted, and only then. Existing permissions keep working whatever the zones say afterwards, revoking is never restricted, updating an existing grant is not affected, and re-sending an unchanged permission set grants nothing new and is therefore not refused.

Nothing that worked before is refused. Granting across contexts previously required credentials for both of them, so every existing caller is covered by the exemption, and the zones only govern the single-credential grant that SCR-1963 newly permits. A deployment without an installed cross-context authority provider is unaffected.

See the general documentation for further details.

SCR-1963

Summary: Shared Account Permissions Across Contexts Require Only the Shared Account's Context Administrator

Effective: 8.54.320 and later

Provisioning a shared account permission for users or groups of another context no longer requires administrator credentials for both contexts. A grant is authenticated against the context of the granting entity, a revocation is accepted from either side - the rule deputy permissions already follow.

  • createSharedAccountPermissions: the shared account's context.
  • deleteSharedAccountPermissions: the shared account's context or the entities' context, whichever accepts the credentials.
  • setSharedAccountPermissions, getSharedAccountPermissions: the shared account's context. The per-context auth sections stay accepted and are still verified when supplied, but are no longer required.

Each call accepts strictly more than before, so no client has to change. The operations also become usable over interfaces that carry a single credential, in particular the HTTP provisioning gateway and SCIM.

See the general documentation for further details.

SCR-1961

Summary: Permanent push keeps its credential in the mail credential vault, persisted regardless of com.openexchange.push.credstorage.rdb

Effective: 8.54.320 and later

Permanent push keeps the credential it needs to run without a session in the mail credential vault (table mail_credential, encrypted with com.openexchange.sessiond.encryptionKey), the way snoozed mail, scheduled mail and the GDPR mail export keep theirs. It does so wherever com.openexchange.push.credstorage.enabled is set to true - persisted in the database, whatever com.openexchange.push.credstorage.rdb says.

Before, com.openexchange.push.credstorage.rdb decided whether the credential was kept in cluster memory (the default) or persisted to the database. It no longer decides that. It only decides where rows of the former storage still live until they are gone: with true, in the credentials table, from where a clean-up job moves them into the vault and deletes them; with false, in cluster memory, from where they are never migrated - they go with the next login of the user, which captures the credential into the vault.

A deployment that enabled the credential storage in order to keep credentials out of the database has to be aware of this: from this version on, the only way to keep them out is to leave com.openexchange.push.credstorage.enabled switched off, at the price of no permanent push for users without a session.

Along with it, deputy permissions managed without DoveAdm report failures of the mailbox access with the codes of the administrative mailbox service (MBADM-0003, MBADM-0004) instead of the former IMAP_DEPUTY- codes for DoveAdm failures, which are gone.

SCR-1945

Summary: New MCP server endpoint for read-only access to mail, calendar, contacts, files and tasks

Effective: 8.54.320 and later

The middleware offers a Model Context Protocol server at /mcp (protocol revision 2026-07-28 and, over the same endpoint, the initialize handshake of revisions 2025-03-26, 2025-06-18 and 2025-11-25, which clients such as claude.ai connectors speak: no session identifier is issued, ping is answered, an unknown method is a JSON-RPC error on 200, and the mirroring headers are optional there, stateless HTTP POST) with read-only tools, prompts and resources. The tools are me_get, mail_search, mail_get, mail_attachment_get, calendar_list_events, calendar_get_event, calendar_free_busy, resources_search, contacts_search, contact_get, users_search, files_search, file_get, tasks_search, task_get, vacation_get, reminders_list and a folder tool per module (mail_folders, calendar_folders, contacts_folders, files_folders, tasks_folders); every list result can be paged through an opaque cursor argument and the nextCursor it returns. The prompts daily_briefing, inbox_triage, find_meeting_slot and catch_up_on chain those tools and are offered only where every tool they drive is available to the caller. Resources are read by URI through the templates ox:///files/{id}, ox:///mail/{folder}/{id} and ox:///mail/{folder}/{id}/attachment/{attachment}, as text or, for anything without a text form, as the first 5 MiB of its bytes; resources/list enumerates nothing. Callers authenticate with a bearer token that the OAuth provider validates, either a JWT from the configured authorization server or a personal access token; tools and resources are visible and usable only with the scopes read_mail, read_calendar, read_contacts, read_files, read_tasks and read_reminders, while me_get is open to every valid token. /.well-known/oauth-protected-resource/mcp serves the RFC 9728 resource metadata. Tool calls and resource reads are rate-limited per user, bounded in how many of one user run at once on a node, and written as one audit line each at level INFO through the logger com.openexchange.mcp.protocol.McpRequestHandler, without argument values or content, and measured through the meters appsuite.mcp.requests, appsuite.mcp.tool.calls and appsuite.mcp.authentications; the core-mw Grafana dashboard gained an MCP row. A bundle that still waits for a needed service, typically the OAuth provider, logs a warning naming it a minute after start. An OpenAPI document describing both paths, the transport headers, every method, the tools, prompts and resources is published as mcp.openapi.json under components/middleware/mcp/<version>/ next to the SCIM and provisioning documents. The endpoint is off by default and needs the chart feature mcp, com.openexchange.mcp.enabled=true and an enabled OAuth provider (com.openexchange.oauth.provider.enabled). The mail tools reach the primary mail account only; secondary and external accounts, which keep their own credentials, are outside a token session's reach. Documentation: documentation/administration/mcp_server.md.

SCR-1938

Summary: Alerting for a failed retention purge of a soft-deleted user

Effective: 8.54.320 and later

The retention job com.openexchange.admin.softdelete.SoftDeleteRetentionExecution counts every purge attempt in the Micrometer counter appsuite.provisioning.softdelete.purges with the tag result=success|failure (Prometheus: appsuite_provisioning_softdelete_purges_total), so an alert can be raised on failures. A failed purge is recorded at the user as the attribute purgeFailed in the namespace softDelete, holding the time and the error, readable over every provisioning API (userAttributes over RMI, user_attributes over gRPC) until the purge succeeds or the user is restored; the restore drops the attribute. The failure is written to the audit trail com.openexchange.provisioning.userLifecycleAuditTrail as well. Before this change a failed purge was only logged at ERROR and retried silently with the next run. Documentation: administration/user_soft_delete.md, administration/cleanup_jobs.md.

SCR-1937

Summary: Audit trail of the user lifecycle: soft-delete, restore, delete and failed purge

Effective: 8.54.320 and later

The provisioning layer writes one line per user and event to the logger com.openexchange.provisioning.userLifecycleAuditTrail at INFO: the soft-deletion, the restore, the deletion for good (by an administrator or by the retention job, then naming the time the user had been soft-deleted), and a failed retention purge. Each line names the acting administrator and, where the request came in over SCIM, the origin the SCIM endpoint records (client, scheme, context). Lines look like:

soft-deleted user 7 in context 1 by oxadmin via scim basic oxadmin in context 1
deleted user 7 in context 1 by soft-delete-retention, soft-deleted since 2026-09-09T11:00:00Z
failed to purge user 7 in context 1 by soft-delete-retention, soft-deleted since 2026-09-09T11:00:00Z: <error>

The logger is meant to be routed to an appender of its own (append-only where the trail is to be kept) with a pattern carrying %lmdc, so the line keeps the tracking identifier and the client address; the appender's timestamp is the time of the event. Without a dedicated appender the lines go to the ordinary log. Documentation: administration/user_soft_delete.md, section "Audit trail".

SCR-1935

Summary: Shares of a soft-deleted user are frozen for every other user

Effective: 8.54.320 and later

While a user is soft-deleted, everything the user has shared is withheld from every other user, without exception: the shared calendars, address books and task folders, the personal files and the files shared one by one, and the shared mail folders (a deputy's access included) are hidden from every other user and cannot be opened, no matter what the stored permissions say. The stored permissions are not touched; the freeze is applied when the effective permission is calculated (folder storage, legacy folder permission, infostore object permissions, the "Shared files" listing, the mail folder tree and the opening of a shared IMAP folder). A restore brings the shares back as they were.

Public folders the user created are no shares and stay accessible. The owner keeps access to the own data, so the data export and the final deletion are unaffected. Before this change, internal shares of a soft-deleted user stayed accessible to the colleagues.

A deputy of a soft-deleted user can neither read the mailbox nor send mail in that user's name: the "send on behalf of" check answers as if the privilege were withheld (MSG-0129), and the grants of a soft-deleted user are absent from the deputy's reverse listings (deputy?action=reverse, reverseIds) until the restore. The stored deputy permissions are not touched.

Documentation: administration/user_soft_delete.md.

SCR-1931

Summary: The SCIM endpoint names its origin in the provisioning log entries and counts its authentications

Effective: 8.54.320 and later

Every SCIM request acts as the context administrator, so the log entries a change produced were indistinguishable from a command line call, and the requests of an identity provider could not be told apart from each other. The endpoint now names itself and the credential it acted with.

  • For the duration of a request the log property com.openexchange.provisioning.origin names the endpoint, the authentication scheme and the credential, for example scim token 7 as oxadmin in context 1; a provisioning token appears by its identifier, a JSON Web Token by its client, basic credentials by their login. The entries of that request carry it, the ones the provisioning services write included. The machine-readable records of extended logging are the exception: they drop the log properties by design.
  • One entry per request goes to the logger com.openexchange.scim.auditTrail, at INFO for the methods that change something and at DEBUG for reads, with method, path, status, duration, caller and, for a create, the location of the new resource. It is a trail of its own, meant to be routed to an appender with additivity="false"; give that appender a pattern with %lmdc, or client address and tracking identifier are lost.
  • New counter appsuite.scim.authentications with the tags scheme (token, basic, jwt, none) and result (accepted, missing, invalid, disabled, forbidden, throttled, unavailable). It tells apart what the status of a request cannot: a wrong password, a token for another context and a scheme switched off by configuration are all answered with 401. Duration, path and status of the requests themselves were already recorded by the REST layer as appsuite.restapi.requests, so no timer was added.
  • A login locked after repeated failed basic authentications is logged with WARN once, when the lock snaps; before, the lock was silent.

Purely additive: no interface changes, no new configuration, and nothing is logged that was not logged before, apart from the new trail and the lock entry.

SCR-1927

Summary: Soft-deleted user state for leavers

Effective: 8.54.320 and later

A user can be soft-deleted, a state between disabled and deleted for the leaver case: the user cannot log in and existing sessions end, is hidden from the global address book, auto-completion, the user listing and group member lists (the memberships are kept), cannot be invited to appointments and answers no free/busy, and the share links and guests the user invited no longer resolve. Mail, files, calendar and contacts are kept and the login name, mail address and aliases stay reserved. mailenabled is left untouched, so a user that was disabled before stays disabled after a restore; the reports count soft-deleted users as disabled. After com.openexchange.user.softDelete.retentionDays (default 30) the clean-up job com.openexchange.admin.softdelete.SoftDeleteRetentionExecution deletes the user for good, hourly on one node of the cluster. The state is set and lifted through the provisioning APIs (RMI, SOAP, gRPC/HTTP) and through SCIM with com.openexchange.scim.deleteMode=softDelete; soft-deleted users are not exposed over SCIM. See administration/user_soft_delete.md.

The deletion for good hands the shared data to the user named when the user was soft-deleted, remembered as the user attribute softDelete/reassignTo; without one it goes to the context administrator as before. The destination is checked again before it is used: one that has been deleted or soft-deleted itself in the meantime falls back to the context administrator rather than failing the purge. Restoring a user forgets the destination; there is no separate call to change it, soft-delete the user again.

SCR-1919

Summary: Removing the calendar access of a shared account permission is persisted when the permission has no mail access

Effective: 8.54.320 and later

OXSharedAccountInterface.setSharedAccountPermissions (RMI, SOAP and gRPC alike) decides per stored permission whether an update has to be written. That decision compared the new calendar configuration against the stored mail configuration instead of the stored calendar configuration. For a permission without mail access, dropping its calendar access therefore compared null with null, counted as unchanged and was never written: the entity kept its calendar access, and the call returned successfully.

The comparison now uses the stored calendar configuration. Permissions with mail access were not affected, since their mail and calendar account identifiers never match. No interface changes.

SCR-1915

Summary: Resource permissions in the provisioning API: returned by getData, validated in simple mode, compared by value

Effective: 8.54.320 and later

Three defects in the handling of resource permissions by the provisioning API (RMI, SOAP and gRPC alike) are fixed; they surfaced while attaching resources to the SCIM service provider.

  • OXResourceInterface.getData for a single resource, and the array form and the gRPC ListResources by identifiers built on it, returned resources without their permissions; the storage applied them to the input object instead of the returned copy. They are now returned, as list and listAll always did.
  • Creating or changing a resource with permissions failed with an internal error whenever com.openexchange.resource.simplePermissionMode was not set explicitly in a properties file: the flag was read without its documented default. It is now read through the lean configuration service, so the default true applies.
  • ResourcePermission compared by identity. The simple-mode validation therefore refused the two configurations it documents, book_directly for group 0 alone and ask_to_book for group 0 together with delegates, and did not recognize the delete marker that resets the permissions. Permissions now compare by entity, kind and privilege, the privilege case-insensitively; the delete marker is recognized by identity only. With the validation working, simple mode now also refuses any list without delegates that is not exactly the default, which it was meant to.

Clients that worked around the failures by not sending permissions are unaffected; clients that sent permissions in simple mode see the documented validation for the first time.

SCR-1886

Summary: Readable 403 page for OpenID Connect logins declined because the user or context is disabled

Effective: 8.54.320 and later

When an OpenID Connect login is declined because the user or the user's context is disabled, the middleware now answers with a readable 403 page telling the user that the account is not available, instead of a bare error page that named the internal user and context identifiers. The identifiers are logged at INFO level instead. The page deliberately offers no link back to the sign-in page: where the sign-in page starts the OpenID Connect flow on its own, such a link only leads back to the identity provider, which authenticates the disabled account again and returns the user to the same page.

The decision is routed through the backend's com.openexchange.oidc.OIDCExceptionHandler, which gains the methods handleContextDisabled(request, response, contextId) and handleUserDisabled(request, response, userId, contextId), mirroring the SAML ExceptionHandler. Both have default implementations rendering the page above, so existing OpenID Connect backends inherit the behavior without changes; a backend can override them to render its own page. The JSON response path is unchanged and keeps answering with LGI-0006.

SCR-1885

Summary: Cache invalidations cross remote Redis sites

Effective: 8.54.320 and later

With remote Redis sites enabled (com.openexchange.redis.sites.enabled), cache invalidations are now repeated on the remote sites' Redis storages, and the messages that invalidate node-local caches of contexts, users, resellers and cache events are published there as well. Two middleware clusters attached to one config database therefore no longer serve stale contexts, users or database assignments after a provisioning change on the other cluster until the cache entries expire. Remote sites are best-effort: an unreachable site is logged, counted in appsuite.redis.remote.failures.total and skipped with a back-off; it never fails the provisioning call. Deployments that only share the databases should set com.openexchange.redis.sites.scope to invalidation to keep sessions on their site. No admin action for deployments without remote sites.

SCR-1883

Summary: Changed creation of the "Collected addresses" folder to the first collected contact instead of login

Effective: 8.54.320 and later

In order to work without a login hook, the contact collector no longer creates a user's "Collected addresses" folder through a login handler at every login. The folder is created the first time the collector has a contact to store, i.e. with the first collected email address that is not yet known as a contact; collector runs that only increment use counts of known contacts create nothing.

  • Until then the user has no "Collected addresses" folder, and modules/mail/contactCollectFolder (io.ox/mail//contactCollectFolder in the JSlob) reports no folder.
  • With the default configuration the switches com.openexchange.user.contactCollectOnMailAccess and com.openexchange.user.contactCollectOnMailTransport are off, so many users only get the folder through an appointment or task with an external participant or through a share notification, and some never do.
  • Deleting the folder works as before; it is recreated with the next collected address instead of at the next login.
  • Existing folders and settings remain valid, no database change or update task is involved, and rolling upgrades are safe. No operator action is required.

Clients that identify the folder through the setting read at login should recognize it through the folder's meta marker __ccf# instead. See the feature documentation for further details.

SCR-1882

Summary: Provisioning read operations now require credentials

Effective: 8.54.320 and later

Provisioning operations that previously answered without checking credentials now require them. This affects the gRPC services DBMigrationService (migration and lock status), LoginCounterService, ShareService (share listings), ConsistencyService and FileChecksumsService (file listings), ExternalAccountService (account listing), DataExportService (task listings) and the access combination lookup of UserService. Registry-wide operations take the master administrator, operations inside a context take that context's administrator; the consistency listings take the master administrator, matching the checkconsistency command-line tool. A caller that sends no or wrong credentials now receives 401 instead of a result. Scripts and monitoring that read these endpoints anonymously have to send credentials from now on. Cross-site forwarding of these read operations is not possible while the underlying RMI methods carry no credentials.

SCR-1881

Summary: Database password no longer part of provisioning responses (HTTP API, SOAP, listdatabase --csv)

Effective: 8.54.320 and later

Provisioning responses no longer carry the password of a registered database. This affects the HTTP API (GET /prov/v1/databases and the register, createSchema and schema-listing responses), the SOAP services (listDatabase, registerDatabase, createSchema, the schema-listing calls and the read and write database inside every returned context) and the command-line tool listdatabase, whose --csv output drops the password column. Registering or changing a database still sends the password, and getDbAccessInfoForSchema of the schema-move interface still returns the access data on purpose. Scripts that read the password from these responses or from the CSV column have to take it from the configdb or from the deployment's configuration instead.

SCR-1859

Summary: Folders shared within an external file storage are stated by the shares action of the folders module

Effective: 8.54.320 and later

The shares action of the folders module states the folders a user shares within an external file storage as well, rather than only the ones of the database. Previously only the storage registered for the requested content type was asked, so the folders of a file storage were not stated at all.

Only a storage that supports being shared that way is affected, so the listing is unchanged for a deployment without such a storage.

SCR-1856

Summary: New file storage service for OpenCloud

Effective: 8.54.320 and later

In order to integrate the files of an OpenCloud instance, the new file storage service opencloud is introduced. It accesses the files through WebDAV, and the spaces, shares and permissions of the instance through the libre graph API, authenticating either with a username and an app token, or through OAuth.

The service is available for the users the capability com.openexchange.capability.filestorage_opencloud is enabled for. An account states the personal space of the user, the project spaces below a virtual folder Spaces, the shared items below a virtual folder Shared, and the trash bins of the spaces below a virtual folder Trash. As OpenCloud limits the storage per space, the quota of a folder is the one of the space it belongs to. As it grants rights through roles, a share states the role that matches the requested permissions best, so a file that is shared for writing is shared with a role that allows deleting it as well, there being no role that allows the one without the other. A share that is meant to be read-only is never granted a role that allows to change the item. An item states the URL that opens it within the web interface of the instance, and a folder states whether it supports permissions, a quota and sorting.

See the feature documentation for further details.

SCR-1851

Summary: Bounded the init container's configdb and middleware readiness waits

Effective: 8.54.320 and later

In order to let an unreachable database fail visibly instead of hanging a pod indefinitely, the core-mw init container now bounds its readiness waits for the configdb and, during initial bootstrapping, for the middleware itself. Previously both the legacy bash and the Go init variant retried forever without sleeping, so a misconfigured MYSQL_HOST left the pod in Init:0/1 with no non-zero exit and no Kubernetes event, while the retry loop consumed a full CPU core. Once a timeout elapses, the init container names the unreachable target and exits non-zero. The reason is also written to the pod's termination log, so it stays readable in the pod status after the restart that follows.

While a wait is running, progress is reported every 30 seconds, for example Still waiting for the MySQL Server at db:3306 after 31s of 300s, so a slow start is visible instead of silent.

A configdb host name that does not resolve is reported after a separate, shorter grace period of 30 seconds, because an unresolvable name is a configuration error rather than a database that is slow to start. The grace period exists because on a fresh install the name legitimately stays unresolvable for a while, for instance while cluster DNS is still starting or a headless service has no endpoints yet. Temporary resolver failures do not count towards it.

Two new Helm chart values control the budgets, both in seconds:

  • initWait.dbTimeout, default 300, passed to the init container as INIT_DB_WAIT_TIMEOUT
  • initWait.middlewareTimeout, default 300, passed as INIT_MW_WAIT_TIMEOUT

The poll intervals and the DNS grace are not exposed as chart values; they are fixed at 2 seconds, 5 seconds for the middleware wait, and 30 seconds respectively. The Go init binary additionally honors INIT_DB_WAIT_INTERVAL, INIT_MW_WAIT_INTERVAL and INIT_DB_DNS_TIMEOUT if they are set by hand, where 0 disables the early exit on an unresolvable name; these accept a Go duration string such as 30s or 2m, and a plain number is read as seconds.

No operator action is required, the values are additive and defaulted. Deployments that legitimately need to wait longer than five minutes for their database have to raise initWait.dbTimeout; a sufficiently high value restores the previous, effectively unbounded behavior.

CLT

SCR-1980

Summary: Added command-line tool jfrrecord for on-demand flight recordings

Effective: 8.54.320 and later

The new command-line tool jfrrecord records a Java Flight Recorder profile on a running middleware node for a fixed duration and writes the file on the host running the tool. It needs no restart and no agent, leaves nothing on the middleware's host, and requires the master administrator's credentials.

  • -f/--file and --overwrite: the target file
  • -d/--duration: 60 seconds by default, at most 10 minutes
  • --settings: default or profile
  • --method-timing: times the given methods (event jdk.MethodTiming)
  • --cpu-time: samples CPU time, Linux only

Each node runs at most one recording. It stops after its duration, is capped at 256 MB, and is discarded when the tool terminates or has not polled for 2 minutes. System properties, environment variables, JVM arguments and process command lines are not recorded.

Method timing requires org.osgi.framework.bootdelegation=jdk.jfr.tracing. The shipped config.ini template now sets it; deployments with their own config.ini have to add it.

Usage:

$ jfrrecord --help
usage: jfrrecord
 -A,--adminuser <adminUser>       Admin username
    --cpu-time                    Additionally samples CPU time (event jdk.CPUTimeSample, experimental). Linux only
 -d,--duration <duration>         How long to record, in seconds ("90" or "90s") or minutes ("5m"). Default is 60
                                  seconds, maximum is 10 minutes
 -f,--file <file>                 The path name of the file to write the recording to; e.g. "/tmp/recording.jfr". The
                                  file is written where this tool runs
 -h,--help                        Prints this help text
 -H,--host <jmxHost>              The optional JMX host (default:localhost)
 -l,--login <jmxLogin>            The optional JMX login (if JMX authentication is enabled)
    --method-timing <filters>     Times invocations of the given methods (event jdk.MethodTiming). Semicolon-separated
                                  fully qualified class names, each optionally followed by "::" and a method name; e.g.
                                  "com.openexchange.drive.impl.DriveServiceImpl::syncFolders". At most 10 filters.
                                  Requires "org.osgi.framework.bootdelegation=jdk.jfr.tracing" on the middleware
    --overwrite                   Overwrite the file if it already exists
 -p,--port <jmxPort>              The optional JMX port (default:9999)
 -P,--adminpass <adminPassword>   Admin password
    --responsetimeout <timeout>   The optional response timeout in seconds when reading data from server (default: 0s;
                                  infinite)
 -s,--password <jmxPassword>      The optional JMX password (if JMX authentication is enabled)
    --settings <settings>         The JFR configuration: "default" (default, low overhead) or "profile" (finer sampling,
                                  more overhead)


The Open-Xchange flight recording tool

SCR-1966

Summary: New command line tool detachprovisioningtoken

Effective: 8.54.320 and later

The new command line tool detachprovisioningtoken ends one context's exposure to a cross-context provisioning token: the token stops opening the context given with -c, keeps working for every other context it opens, and is deleted only if this was the last one. A cross-context token is issued by an administrator standing above the contexts, so the context reached into has no part in it; listprovisioningtokens with --reaching-into shows which tokens open a context, and this tool ends such an access. It is not a revocation - revokeprovisioningtoken ends a token everywhere at once - and no lasting veto, since an administrator above the contexts may issue a token covering the context again. Detaching a context the token does not open is reported on the error stream and ends with exit code 0. It ships with open-xchange-admin next to the other administration tools and calls the RMI interface OXProvisioningTokenInterface, so it needs neither the HTTP gateway nor gRPC access; authorization follows every other operation inside a context: the context administrator, a reseller administrator owning the context or, where MASTER_ACCOUNT_OVERRIDE permits it, the master administrator.

Usage: detachprovisioningtoken
 -h,--help                                        Prints a help text
    --environment                                 Show info about commandline environment
    --nonl                                        Remove all newlines (\n) from output
    --responsetimeout <responsetimeout>           response timeout in seconds for reading response from the backend (default 0s; infinite)
 -A,--adminuser <adminuser>                     ? Admin username
 -P,--adminpass <adminpass>                     ? Admin password
 -c,--contextid <contextid>                     * The context to detach
    --token-id <id>                             * The identifier of the token, as listprovisioningtokens --reaching-into shows it

Entries marked with an asterisk (*) are mandatory.
Entries marked with an question mark (?) are mandatory depending on your
configuration.
Entries marked with a pipe (|) are mandatory for one another which means that
at least one of them must be set.

SCR-1942

Summary: New command line tool revokeprovisioningtoken

Effective: 8.54.320 and later

The new command line tool revokeprovisioningtoken revokes a provisioning token given by --token-id, the identifier listprovisioningtokens shows; its secret is refused from then on. Given a context with -c, a token bound to that context is revoked; without a context, a cross-context token, which only the master administrator or, where MASTER_ACCOUNT_OVERRIDE permits it, a reseller administrator owning every one of the contexts may revoke. A token that does not exist, or lies out of the caller's reach, is reported on the error stream, so a revocation that did not happen is not mistaken for one that did, and ends with exit code 0, like deletesecondaryaccount does for an unknown account. It ships with open-xchange-admin next to the other administration tools and calls the RMI interface OXProvisioningTokenInterface, so it needs neither the HTTP gateway nor gRPC access; authorization for a context follows every other operation inside a context: the context administrator, a reseller administrator owning the context or, where MASTER_ACCOUNT_OVERRIDE permits it, the master administrator.

Usage: revokeprovisioningtoken
 -h,--help                                        Prints a help text
    --environment                                 Show info about commandline environment
    --nonl                                        Remove all newlines (\n) from output
    --responsetimeout <responsetimeout>           response timeout in seconds for reading response from the backend (default 0s; infinite)
 -A,--adminuser <adminuser>                     ? Admin username
 -P,--adminpass <adminpass>                     ? Admin password
 -c,--contextid <contextid>                       The id of the context
    --token-id <id>                             * The identifier of the token, as listprovisioningtokens shows it

Entries marked with an asterisk (*) are mandatory.
Entries marked with an question mark (?) are mandatory depending on your
configuration.
Entries marked with a pipe (|) are mandatory for one another which means that
at least one of them must be set.

SCR-1941

Summary: New command line tool listprovisioningtokens

Effective: 8.54.320 and later

The new command line tool listprovisioningtokens lists provisioning tokens, expired ones included: identifier, the contexts a token opens, label, scope, creator, creation time, expiration time and last successful use, as ISO-8601 in UTC. Given a context with -c, the tokens bound to that context are listed; without a context, the cross-context tokens the caller stands above: all of them for the master administrator, which needs no MASTER_ACCOUNT_OVERRIDE, and for a reseller administrator those opening only contexts it owns, which needs it as every reseller access to a context does. Secrets are never shown.--csv gives CSV output, with empty fields where a token does not expire or was never used. Given a context together with --reaching-into, the listing runs the other way round: the cross-context tokens that open that context, which its administrator has no other way to see; each is shown naming that context and no other. It ships with open-xchange-admin next to the other administration tools and calls the RMI interface OXProvisioningTokenInterface, so it needs neither the HTTP gateway nor gRPC access; authorization for a context follows every other operation inside a context: the context administrator, a reseller administrator owning the context or, where MASTER_ACCOUNT_OVERRIDE permits it, the master administrator.

Usage: listprovisioningtokens
 -h,--help                                        Prints a help text
    --environment                                 Show info about commandline environment
    --nonl                                        Remove all newlines (\n) from output
    --responsetimeout <responsetimeout>           response timeout in seconds for reading response from the backend (default 0s; infinite)
 -A,--adminuser <adminuser>                     ? Admin username
 -P,--adminpass <adminpass>                     ? Admin password
 -c,--contextid <contextid>                       The id of the context
    --csv                                         Format output to csv

Entries marked with an asterisk (*) are mandatory.
Entries marked with an question mark (?) are mandatory depending on your
configuration.
Entries marked with a pipe (|) are mandatory for one another which means that
at least one of them must be set.

SCR-1940

Summary: New command line tool createprovisioningtoken

Effective: 8.54.320 and later

The new command line tool createprovisioningtoken creates a provisioning token, the bearer secret an automated client such as an identity provider driving the SCIM service provider or a script driving the provisioning API authenticates with. Given a context with -c, the token is bound to that context; given --contexts with at least two context identifiers instead, a cross-context token is created that opens every one of them, which only the master administrator or a reseller administrator owning every one of the contexts, and only where MASTER_ACCOUNT_OVERRIDE lets an administrator reach into a context at all may do. --label says what the token is for, --scope names the interface it opens, scim or provisioning (defaults to scim for a context and is mandatory together with --contexts, so that moving a client from one context to several cannot silently change what its token opens), and --expires takes a date as yyyy-MM-dd (midnight UTC) or a date and time with offset such as 2027-01-01T12:00:00Z; without it the token does not expire. The tool prints the identifier and, this once, the secret of the form ox_<context-id>_<64 hex characters>, or ox_x_<64 hex characters> for a cross-context token. It ships with open-xchange-admin next to the other administration tools and calls the RMI interface OXProvisioningTokenInterface, so it needs neither the HTTP gateway nor gRPC access; authorization for a context follows every other operation inside a context: the context administrator, a reseller administrator owning the context or, where MASTER_ACCOUNT_OVERRIDE permits it, the master administrator.

Usage: createprovisioningtoken
 -h,--help                                        Prints a help text
    --environment                                 Show info about commandline environment
    --nonl                                        Remove all newlines (\n) from output
    --responsetimeout <responsetimeout>           response timeout in seconds for reading response from the backend (default 0s; infinite)
 -A,--adminuser <adminuser>                     ? Admin username
 -P,--adminpass <adminpass>                     ? Admin password
 -c,--contextid <contextid>                     | The id of the context
    --contexts <contexts>                       | The contexts a cross-context token opens, comma-separated, at least two; instead of a single context. Needs the master administrator or a reseller administrator owning every one of them
    --label <label>                             * What the token is for, for example the identity provider using it; at most 128 characters
    --scope <scope>                               The interface the token opens: scim or provisioning. Defaults to scim for a context; mandatory together with --contexts
    --expires <date>                              When the token expires: yyyy-MM-dd (midnight UTC) or a date and time with offset such as 2027-01-01T12:00:00Z. Without, it does not expire

Entries marked with an asterisk (*) are mandatory.
Entries marked with an question mark (?) are mandatory depending on your
configuration.
Entries marked with a pipe (|) are mandatory for one another which means that
at least one of them must be set.

SCR-1930

Summary: New option --soft-deleted for listuser

Effective: 8.54.320 and later

listuser gains the option --soft-deleted that lists the soft-deleted users of the context only; the search pattern and the guest options do not apply to it. The ordinary listing keeps including soft-deleted users. The CSV output of the user listings (--csv) carries the new column SoftDeleted, the date of the soft-deletion, empty for every other user.

Usage: listuser 
 -h,--help                                         Prints a help text          
    --environment                                  Show info about commandline environment
    --nonl                                         Remove all newlines (\n) from output
    --responsetimeout <responsetimeout>            response timeout in seconds for reading response from the backend (default 0s; infinite)
 -c,--contextid <contextid>                      * The id of the context       
 -A,--adminuser <adminuser>                      ? Admin username              
 -P,--adminpass <adminpass>                      ? Admin password              
    --csv                                          Format output to csv        
    --includeguests                                Include guest users         
    --excludeusers                                 Exclude users, only show guests
    --soft-deleted                                 List the soft-deleted users of the context only; the search pattern and the guest options do not apply.
 -s,--searchpattern <searchpattern>                The search pattern which is used for listing. This applies to name.
 -i,--ignorecase                                   Whether to perform look-up case-insensitive
    --length <length>                              Limit result size           
    --offset <offset>                              Set offset for limited result size

Entries marked with an asterisk (*) are mandatory.
Entries marked with an question mark (?) are mandatory depending on your
configuration.
Entries marked with a pipe (|) are mandatory for one another which means that
at least one of them must be set.

SCR-1929

Summary: New command line tool restoreuser

Effective: 8.54.320 and later

The new command line tool restoreuser lifts the soft-deleted state set by softdeleteuser: the user appears in the address book and in group member lists again, can be invited again and, unless disabled through mailenabled, can log in again. A user that is not soft-deleted is rejected. The user is addressed by -i or -u in the context given by -c.

Usage: restoreuser 
 -h,--help                                         Prints a help text          
    --environment                                  Show info about commandline environment
    --nonl                                         Remove all newlines (\n) from output
    --responsetimeout <responsetimeout>            response timeout in seconds for reading response from the backend (default 0s; infinite)
 -c,--contextid <contextid>                      * The id of the context       
 -A,--adminuser <adminuser>                      ? Admin username              
 -P,--adminpass <adminpass>                      ? Admin password              
 -i,--userid <userid>                            | Id of the user              
 -u,--username <username>                        | Username of the user        

Entries marked with an asterisk (*) are mandatory.
Entries marked with an question mark (?) are mandatory depending on your
configuration.
Entries marked with a pipe (|) are mandatory for one another which means that
at least one of them must be set.

SCR-1928

Summary: New command line tool softdeleteuser

Effective: 8.54.320 and later

The new command line tool softdeleteuser marks a user as soft-deleted, the leaver state between disabled and deleted: the user cannot log in, is hidden from the address book and from group member lists, cannot be invited, and the share links and guests the user invited stop working, while mail, files, calendar and contacts are kept and the login name stays reserved. After com.openexchange.user.softDelete.retentionDays the user is deleted for good; until then restoreuser brings the user back. The context administrator, guests, shared accounts and users that are already soft-deleted are rejected. The user is addressed like with deleteuser, by -i or -u in the context given by -c.

Usage: softdeleteuser 
 -h,--help                                         Prints a help text          
    --environment                                  Show info about commandline environment
    --nonl                                         Remove all newlines (\n) from output
    --responsetimeout <responsetimeout>            response timeout in seconds for reading response from the backend (default 0s; infinite)
 -c,--contextid <contextid>                      * The id of the context       
 -A,--adminuser <adminuser>                      ? Admin username              
 -P,--adminpass <adminpass>                      ? Admin password              
 -i,--userid <userid>                            | Id of the user              
 -u,--username <username>                        | Username of the user        
 -r,--reassign <reassign>                          The user id shared data will be assigned to once the retention period has passed. If omitted the context admin will be used instead.
    --no-reassign                                  If set all shared data will be deleted instead of being assigned once the retention period has passed.

Entries marked with an asterisk (*) are mandatory.
Entries marked with an question mark (?) are mandatory depending on your
configuration.
Entries marked with a pipe (|) are mandatory for one another which means that
at least one of them must be set.

The options -r/--reassign <id> and --no-reassign name the user the shared data is reassigned to once the retention period has passed, exactly as on deleteuser: --reassign hands it to that user, --no-reassign drops it, neither leaves it to the context administrator. The destination is checked when it is named and again before it is used.

Changed defaults

SCR-1998

Summary: More carrier threads for virtual threads by default

Effective: 8.54.320 and later

The middleware now starts with -Djdk.virtualThreadScheduler.parallelism=256, the number of carrier threads its virtual threads run on, unless a JAVA_OPTS_* value already sets it. A virtual thread that loads a class is pinned to its carrier: with no more carriers than CPU cores, requests loading the same class at once could pin them all while the holder of a class loader lock waited for a carrier, and the middleware stopped answering. Carrier threads are ordinary platform threads, and idle ones cost little. Set the option in JAVA_OPTS_OTHER or in ox-scriptconf.sh to choose another value.

Configuration

SCR-2000

Summary: New configuration options for anti-virus scanning

Effective: 8.54.320 and later

New options to enforce anti-virus scans and to secure and bound the connection to the ICAP service.

  • com.openexchange.antivirus.enforce Scans every download of a user who has the anti-virus feature enabled, regardless of the client's scan parameter. Items that cannot be scanned are refused, as is every download while the anti-virus service is unavailable. Default false. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.icap.client.connectTimeout Time-out in milliseconds for establishing the connection to the ICAP server. A value less than or equal to 0 leaves it to the operating system. Default 5000. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.icap.client.requestTimeout Maximum time in milliseconds a single ICAP request may take once connected, sending the item included. A value less than or equal to 0 imposes no limit. Default 120000. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.icap.client.tls Contacts the ICAP server via TLS. Certificate and host name are always verified, against com.openexchange.icap.client.tls.truststore or the JDK's default trust store, independent of com.openexchange.net.ssl.trustlevel. Default false. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.icap.client.tls.truststore Path of a PKCS#12 or JKS trust store for TLS connections to the ICAP server, e.g. holding a custom CA. If empty, the JDK's default trust store is used. Default empty. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.icap.client.tls.truststorePassword Password of the trust store given by com.openexchange.icap.client.tls.truststore. Default empty. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-1996

Summary: New configuration options for the Mobile API

Effective: 8.54.320 and later

The following options control the Mobile API at /mobile/v1. All are reloadable and have no dedicated properties file.

  • com.openexchange.mobile.api.enabled

Whether the API answers. Default false. Config-cascade aware: the server-level value decides whether /mobile/v1 answers at all, a lower level whether a signed-in user may use it.

  • com.openexchange.mobile.auth.mode

How apps sign in: token for personal access tokens, idp for the operator's identity provider. Default token.

  • com.openexchange.mobile.auth.idp.issuer

Mode idp: the OpenID Connect issuer published by auth/config. Empty by default. Without it and com.openexchange.mobile.auth.idp.clientId, auth/config answers 500.

  • com.openexchange.mobile.auth.idp.clientId

Mode idp: the public client identifier of the app. Empty by default.

  • com.openexchange.mobile.auth.idp.scopes

Mode idp: the scopes, comma-separated, the app requests. Empty by default.

  • com.openexchange.mobile.auth.idp.audience

Mode idp: the resource indicator (RFC 8707) the app passes, if the identity provider needs one. Empty by default. It is published only; a token's audience is checked when com.openexchange.oauth.provider.jwt.audience is set.

  • com.openexchange.mobile.auth.idp.redirectUris.ios, com.openexchange.mobile.auth.idp.redirectUris.android

Mode idp: the redirect URIs of the two apps. Empty by default.

SCR-1994

Summary: New configuration options for sending a mail at most once

Effective: 8.54.320 and later

The following options control the Idempotency-Key header and the client message identifier of mail send requests.

  • com.openexchange.ajax.idempotency.enabled Whether actions honor the Idempotency-Key header. Default true. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.ajax.idempotency.retention How long the result of a request other than a send is kept for a retry. Default 24h. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.ajax.idempotency.sendRetention How long the result of sending a mail is kept for a retry. Default 7d. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.ajax.idempotency.maxResultSize The largest result kept for a retry; 0 keeps none. Default 64KB. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.ajax.idempotency.claimTimeout How long the key of a running request lives without being renewed; at least 30s. Default 5m. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mail.sentMessageIds.enabled Whether a mail with a client message identifier is sent at most once. Default true. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mail.sentMessageIds.retention How long the client message identifier of a sent mail is remembered; each takes about 0.3 KB in Redis. Default 30d. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-1992

Summary: New configuration options for signing in for a personal access token

Effective: 8.54.320 and later

The following options control the sign-in with user name and password for a personal access token through login?action=accessToken.

  • com.openexchange.accesstoken.signin.enabled Whether a client may sign in for a token. Default false. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.accesstoken.signin.defaultScopes The scopes, comma-separated, a token gets when the client names none; scopes the user cannot grant are left out. Default read_mail,write_mail,read_contacts. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.accesstoken.signin.defaultLifetimeDays The lifetime in days of a token when the client names no expiry, capped by com.openexchange.accesstoken.maxLifetimeDays. A value less than or equal to 0 (zero) is ignored and the default is used. Default 90. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.accesstoken.signin.allowedClients The client identifiers, comma-separated, that may sign in; empty allows every client. Default empty. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.accesstoken.signin.challengeLifetime How long in milliseconds a user with a second factor has to confirm the sign-in; the password is kept sealed for that time. A value less than or equal to 0 (zero) or above one hour is ignored and the default is used. Default 300000. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.accesstoken.signin.rateLimit.perLogin How many sign-in attempts a login name may make in the time window, counted cluster-wide before the password is checked; the same number bounds the second-factor codes and SMS per user. A sign-in with the full password or a confirmed second factor clears the count. 0 or less disables this limit. Default 5. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.accesstoken.signin.rateLimit.perIp How many failed sign-ins a client address may have in the time window, counted cluster-wide; the address is the transport address, IPv6 per /64 network. 0 or less disables this limit. Default 20. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.accesstoken.signin.rateLimit.timeWindow The time window in milliseconds of the limits, between 10 seconds and 12 hours; values outside are clamped. 0 or less disables the limits per login name and address. Default 900000. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-1989

Summary: New plural existing*Secrets list values in the core-mw Helm chart

Effective: 8.54.320 and later

In order to take sensitive configuration from several Secrets, for example one ExternalSecret per credential, without merging them into one Secret first, every additive existing*Secret value of the core-mw Helm chart gets a plural twin that accepts a list of further Secret names in the release namespace:

  • existingPropertiesSecrets
  • existingUISettingsSecrets
  • existingMetaSecrets
  • existingContextSetsSecrets
  • existingETCFilesSecrets
  • existingETCBinariesSecrets
  • existingYAMLFilesSecrets
  • existingEnvSecrets

The singular value stays supported and is mounted first; a name given twice is used once. The file-based lists are projected into the same directory as the singular Secret, so the keys of all listed Secrets have to be distinct, and a duplicate property is still decided by the numeric file-name prefix, not by list order. Entries of existingEnvSecrets become further envFrom sources after existingEnvSecret; a later entry wins on a duplicate key, and extraEnv wins over all of them. The lists can be set per role or per node type under roles.<role>.values and scaling.nodes.<type>.values, where they replace the global list rather than extend it. Adding, removing or editing a listed Secret changes the checksum/existingSecrets pod annotation and rolls the pods. All lists default to empty; existing deployments are unaffected and do not roll on upgrade. existingASConfigSecret, redis.existingSecret and mysql.existingSecret stay singular.

SCR-1982

Summary: The folders of a Nextcloud account are arranged like the ones of an OpenCloud account

Effective: 8.54.320 and later

The root folder of a Nextcloud account no longer holds the files of the user directly. It holds the virtual folders Personal, Shares and Team folders, along with Trash, where Shares holds Shared with me, Shared with others and Shared via link. The items of the user are listed within Personal, Shared with me or Team folders, depending on the way the instance mounts them, so the identifier of an item is unchanged - only the folder it states as its parent is.

Within the meta of a folder, the object nextcloud states:

  • folderType - the kind of the folder, one of personal, shared, sharedWithMe, sharedWithOthers, sharedViaLink, teamFolders, teamFolder and trash, absent for a folder of the user.

  • quota - the quota of the storage the folder denotes, stated for Personal and for each team folder, holding total and used in bytes, where a storage the instance does not limit states -1 as its total.

  • backwardLink - the link that opens the folder within the web interface of the instance, which a file states within its meta as well.

The virtual folders are of the type VIRTUAL_FOLDER, so a traversal of the folder tree passes them over, see https://jira.atlassian.open-xchange.com/browse/SCR-1970 .

SCR-1981

Summary: New properties of the OAuth provider of a Nextcloud instance

Effective: 8.54.320 and later

An account of the Nextcloud file storage may be linked to an OAuth account from now on, see https://jira.atlassian.open-xchange.com/browse/SCR-1981 , which the new OAuth service with the service identifier nextcloud is introduced for. It is configured through the following properties, all of which are reloadable and evaluated through the config cascade, so a deployment may integrate a different instance per context or user:

  • com.openexchange.oauth.nextcloud.enabled, default false, states whether the service is offered at all.
  • com.openexchange.oauth.nextcloud.hostname, empty by default, states the host of the instance the deployment integrates with. It is required if the service is enabled.
  • com.openexchange.oauth.nextcloud.apiKey and com.openexchange.oauth.nextcloud.apiSecret, both empty by default, state the client the deployment authenticates with. Both are required: as opposed to the OpenCloud provider, the Nextcloud one authenticates as a confidential client only, so a client without a secret is not supported and the service is not offered until both hold a value.
  • com.openexchange.oauth.nextcloud.redirectUrl and com.openexchange.oauth.nextcloud.productName, the ordinary properties of an OAuth service.
  • com.openexchange.oauth.nextcloud.authorizationUrl, com.openexchange.oauth.nextcloud.tokenUrl and com.openexchange.oauth.nextcloud.userInfoUrl, empty by default, state the endpoints of an identity provider in front of the instance, e.g. Keycloak. Left empty, the endpoints of the instance itself are used.
  • com.openexchange.oauth.nextcloud.scope, default openid profile email offline_access, states the scopes that are requested when the deployment is authorized, separated by spaces.

An account that authenticates with a username and an app token needs none of these, the OAuth service being optional for the storage. The storage is registered regardless, as long as the package open-xchange-oauth is enabled, see SCR-1855.

SCR-1978

Summary: New configuration options for live change events

Effective: 8.54.320 and later

The new push notification transport sse delivers notifications to live change streams (Server-Sent Events). The following options control it.

  • com.openexchange.pns.transport.sse.enabled Whether the transport is enabled. It can be refined per client and topic by appending .<client> and .<client>.<topic>. Default false. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.pns.transport.sse.pingInterval The interval in milliseconds in which an open stream refreshes its presence and sends a ping event to the client; a presence that is not refreshed expires after twice this interval. Default 30000. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.pns.transport.sse.maxConnectionsPerUser The maximum number of streams a user may have open across the cluster. Opening one more closes the user's oldest stream with reason replaced. A value less than or equal to 0 (zero) disables the limit. Default 5. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.pns.transport.sse.maxConnectionsPerNode The maximum number of streams open on one node. Further requests are rejected with HTTP status 503 and a Retry-After header, so the client can reconnect to another node. A value less than or equal to 0 (zero) disables the limit. Default 5000. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.pns.transport.sse.maxLifetime The maximum lifetime of a stream in milliseconds. Once reached, the stream ends with reason lifetime and the client reconnects. A value less than or equal to 0 (zero) is ignored and the default is used. Default 1800000 (30 minutes). Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.pns.transport.sse.tokenCheckInterval The interval in milliseconds in which the bearer token of a stream is validated again; a stream whose token was revoked or expired then ends with reason token_invalid. Keep it below 5 minutes, the time an idle OAuth session lives. A value less than or equal to 0 (zero) is ignored and the default is used. Default 120000. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.imap.liveChanges.mode How changes made outside the middleware, e.g. by another mail client, are noticed for live change streams of users whose primary account is IMAP. poll looks at the mailbox of a user with an open stream once per pollInterval, in one LIST "" "*" RETURN (STATUS (MESSAGES UIDNEXT UIDVALIDITY HIGHESTMODSEQ)) command on a pooled connection; it needs the IMAP extensions LIST-EXTENDED and LIST-STATUS, and CONDSTORE for changes that leave the message counts alone. off leaves such changes unnoticed. Changes made through the middleware are reported either way. Default poll. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.imap.liveChanges.pollInterval The interval in milliseconds in which such a mailbox is looked at. Streams are handled every 5 seconds, so shorter values take effect as 5 seconds. Default 10000. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.imap.liveChanges.maxWatches The maximum number of users a node watches this way. Streams of further users still report the changes made through the middleware. A value less than or equal to 0 (zero) disables the limit. Default 5000. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.mail.liveChanges.echoWindow The time in milliseconds within which the mail server’s report of a change the middleware made itself is left out, so that a live change stream sees such a change once. It has to exceed the time the mail server needs to report a change, e.g. com.openexchange.imap.liveChanges.pollInterval. A value less than or equal to 0 (zero) switches the suppression off and reports the change twice. Default 15000. Reloadable, config-cascade aware. No dedicated properties file.

SCR-1975

Summary: New Properties to Configure Default Alarms for Newly Provisioned Calendar Accounts

Effective: 8.54.320 and later

Two new lean configuration properties define a default alarm that is taken over into a user's calendar settings when the internal calendar account is provisioned:

  • com.openexchange.calendar.defaultAlarmDate for appointments whose start date is of type date, i.e. all-day appointments
  • com.openexchange.calendar.defaultAlarmDateTime for appointments whose start date is of type date-time

Each value is a trigger duration relative to the start of the appointment as defined in RFC 5545, e.g. -PT15M or PT9H, and yields a single alarm with action DISPLAY. Both default to an empty value, are reloadable and config-cascade aware down to scope user. Existing accounts are not touched, and a legacy defaultReminder setting already stored for the user takes precedence. No operator action is required; without a value there is no default reminder, as before.

See the property documentation for further details.

SCR-1971

Summary: New properties matching the users and groups of a Nextcloud instance with the ones of the server

Effective: 8.54.320 and later

The Nextcloud file storage states the shares of an item as its permissions, and applies the permissions a client states as shares, which requires the users and groups of the instance to be matched with the ones of the server. Four properties are introduced for that, all of them reloadable and evaluated through the config cascade:

  • com.openexchange.file.storage.nextcloud.entityResolver.attribute, default mail, states whether a user is matched by its mail address or by the name it logs in with, the respective other one being used as a fallback.

  • com.openexchange.file.storage.nextcloud.entityResolver.mappingFile, empty by default, states the path to a file that maps the entities of both systems statically, which takes precedence over matching by attribute. It states one entry per line, ':'-separated: contextId:nextCloudUserId:oxUserId for a user, group:contextId:nextCloudGroupId:oxGroupId for a group.

  • com.openexchange.file.storage.nextcloud.entityResolver.folderPermissions, default false, expresses the shares of a listed folder as its permissions, which is a request per shared folder.

  • com.openexchange.file.storage.nextcloud.entityResolver.objectPermissions, default false, expresses the shares of a listed file as its object permissions, which is a request per shared file.

  • com.openexchange.file.storage.nextcloud.retryAfterErrorInterval, default 300, the period, in seconds, an account whose credentials the Nextcloud instance rejected is not asked again for.

Disabled, a shared item states that it is shared, but not with whom. Neither property applies to the permissions a client states for an item, which are applied to its shares in any case.

A deployment that registers a NextCloudEntityResolver of its own supersedes the default implementation, which is registered with the default service ranking.

SCR-1967

Summary: New properties to configure authentication and TLS for the Cassandra connection

Effective: 8.54.320 and later

In order to connect to Cassandra clusters that require authentication or encryption in transit, the connection opened by bundle com.openexchange.nosql.cassandra is now configurable through new lean configuration properties:

  • com.openexchange.nosql.cassandra.username - the user name to authenticate with; empty by default, in which case no authentication is performed at all
  • com.openexchange.nosql.cassandra.password - the accompanying password
  • com.openexchange.nosql.cassandra.authProviderClass - the driver's authentication provider, PlainTextAuthProvider by default
  • com.openexchange.nosql.cassandra.ssl - encrypts the connections using TLS, false by default
  • com.openexchange.nosql.cassandra.sslKeystorePath and com.openexchange.nosql.cassandra.sslKeystorePassword - the key store holding the client certificate, for clusters that require client certificate authentication

Encryption follows the server's central SSL configuration: the trust material, the enabled protocols and the cipher suites are taken from the properties with prefix com.openexchange.net.ssl., and the node's host name is matched against its certificate unless com.openexchange.net.ssl.hostname.verification.enabled is turned off. A certificate authority that is unknown to the JVM therefore belongs into the central custom trust store; there is no Cassandra-specific trust store.

None of the properties is reloadable or config-cascade aware; they are evaluated once when the session is built, so a changed credential requires a restart. The change is purely additive - with an empty user name and TLS disabled the resulting driver configuration is unchanged, so existing installations are unaffected.

Note that -Ddatastax-java-driver.advanced.auth-provider.* JVM arguments continue to take precedence over the authentication properties. A deployment still passing credentials that way keeps working, but a leftover argument silently overrides the configured value.

A rejected credential is now reported as an authentication error instead of unreachable contact points, and is retried on the same timer, so that a secret which has not been rolled out yet degrades the node instead of failing bundle start.

SCR-1955

Summary: New configuration options for the mail credential vault's token exchange

Effective: 8.54.320 and later

The mail credential vault keeps what lets a feature reach a mailbox without a live session - snoozed mail, scheduled mail, the GDPR mail export and permanent push. These options say that what it keeps is obtained through an OAuth token exchange (RFC 8693) rather than taken from the session as it is. Each of them also exists with a feature identifier appended - snoozed-mail, scheduled-mail, gdpr-export or push - and that value wins for that feature, so a deployment configures the exchange once and can still say something different about a single one. A feature added later needs no option of its own.

  • com.openexchange.mail.credential.oauth.tokenExchange Whether the credentials kept for a feature come from a token exchange. Set it to false behind a feature identifier to leave that feature out of what all others do; left empty there, the feature inherits. Where a deployment configured com.openexchange.mail.snoozed.oauth.tokenExchange or com.openexchange.mail.scheduled.oauth.tokenExchange before these options existed, those values are still read and take precedence over the shared one, so nothing has to be migrated. Default false. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.mail.credential.oauth.tokenExchange.backendPath The path of the OpenID Connect back-end to exchange with. Empty means the back-end the session itself came from. Default empty. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.mail.credential.oauth.tokenExchange.scope The OAuth scope to request. Empty means none is requested. Worth setting per feature, since reaching a mailbox needs less than sending through it. Default empty. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.mail.credential.oauth.tokenExchange.additionalParameters Further parameters for the exchange request, as a single key=value pair; multiple pairs are separated by &. Typically selects the exchange policy at the OAuth server, e.g. usecase=mail-snooze, which is per feature by nature. Empty means none are sent. Default empty. Reloadable, config-cascade aware. No dedicated properties file.

SCR-1954

Summary: New configuration options for the Web Push transport and WebDAV-Push

Effective: 8.54.320 and later

New configuration for the Web Push transport of the push notification service (bundle com.openexchange.pns.transport.webpush, package open-xchange-pns-impl) and for the WebDAV-Push extension for CalDAV and CardDAV (bundle com.openexchange.dav.push, package open-xchange-dav). All properties are lean properties with built-in defaults and no properties file; the feature is off by default.

  • com.openexchange.pns.transport.webpush.*: enabling the transport (with the usual per-client and per-topic suffixes), the VAPID key - preferably as a Kubernetes secret through the key store service, alternatively as properties -, the egress policy for the client-supplied push resources (HTTPS only, host allowlist, local endpoints, "trust all" handling), the TTL and Urgency headers, the maximum lifetime of a subscription and the number of subscriptions a user may hold.
  • com.openexchange.httpclient.webpush.*: the managed HTTP client the transport delivers with, tuned through the generic HTTP client keys; the transport ships with its own defaults (short timeouts, larger pool, hard timeouts enabled).
  • com.openexchange.dav.push.*: the config-cascade aware switch offering WebDAV-Push to CalDAV/CardDAV clients (default false), the maximum lifetime of WebDAV-Push subscriptions, and the secret the opaque collection topics are derived with.

Rotating the VAPID key invalidates the existing subscriptions at the push services until the clients re-register with the new key; all nodes of a cluster must use the same key.

See the general documentation, as well as the configuration documentation for the Web Push transport and for WebDAV-Push for further details.

SCR-1934

Summary: Removed the property com.openexchange.antivirus.mode along with the experimental streaming operation mode

Effective: 8.54.320 and later

The property com.openexchange.antivirus.mode (default double-fetch) is no longer evaluated and has been removed; deployments still setting it can simply drop it. Its experimental streaming value never returned the scanned content to the requesting client and left the ICAP connection open after every scan, so the mode has been removed along with the property. Anti-Virus scanning now always behaves as it did with the previous default.

The Java method AntiVirusService.canStream(), which only reported that mode, has been removed as well.

SCR-1926

Summary: New configuration options for soft-deleted users

Effective: 8.54.320 and later

Options for the soft-deleted user state, the leaver state between disabled and deleted.

  • com.openexchange.user.softDelete.retentionDays The number of days a soft-deleted user is kept before the clean-up job com.openexchange.admin.softdelete.SoftDeleteRetentionExecution deletes the user for good, the same way an explicit delete through the provisioning API would. 0 keeps soft-deleted users until an administrator deletes or restores them. Default 30. Reloadable, config-cascade aware. No dedicated properties file.

  • com.openexchange.scim.deleteMode Accepts the additional value softDelete: a SCIM DELETE of a user soft-deletes the user instead of deactivating or deleting it. Default deactivate, unchanged. Reloadable, config-cascade aware. No dedicated properties file.

SCR-1912

Summary: New property com.openexchange.oauth.provider.jwt.audience; EC and RSA-PSS signatures accepted

Effective: 8.54.320 and later

Two changes to the OAuth provider's validation of JSON Web Tokens in mode expect_jwt, closing gaps found while attaching the SCIM service provider to it.

  • New property com.openexchange.oauth.provider.jwt.audience: a comma separated list of audiences (claim aud) tokens are accepted for; a token has to carry one of them. Empty, the default, keeps the audience unchecked, as before. Reloadable and config-cascade aware. Operators are advised to set it, so that only tokens minted for the deployment pass.
  • Tokens signed with the RSA-PSS (PS256/384/512) and EC (ES256/384/512) algorithms are accepted next to RS256/384/512, according to the key type in the JWK set. Symmetric algorithms and none remain refused.
  • An empty com.openexchange.oauth.provider.allowedIssuer still accepts every issuer whose key the JWK set holds, but is now logged as a warning on start and reload.

SCR-1911

Summary: New property com.openexchange.scim.allowJwt

Effective: 8.54.320 and later

com.openexchange.scim.allowJwt defines whether the SCIM endpoint accepts JSON Web Tokens issued by the identity provider next to provisioning tokens. The token is validated by the OAuth provider (com.openexchange.oauth.provider.mode=expect_jwt), has to belong to the context, carry the scope scim and name the context administrator as subject. Reloadable and config-cascade aware down to the context. Defaults to false, so an enabled OAuth provider does not open the endpoint unnoticed. No operator action is required by default.

SCR-1902

Summary: New properties com.openexchange.scim.deleteMode, com.openexchange.scim.allowBasicAuth and com.openexchange.scim.allowUnauthenticatedDiscovery

Effective: 8.54.320 and later

Three lean configuration properties control the new SCIM service provider. All three are reloadable and config-cascade aware down to the context.

  • com.openexchange.scim.deleteMode defines what DELETE /scim/v2/contexts/{context_id}/Users/{id} does: deactivate keeps the account and its data and only refuses login, delete removes the account and its data the way the provisioning API does. It defaults to deactivate, so a misconfigured identity provider cannot wipe a context in one sync cycle.
  • com.openexchange.scim.allowBasicAuth defines whether the SCIM endpoint accepts HTTP basic credentials of administrators next to provisioning tokens. It defaults to true; false makes the endpoint token-only, which exposes no password to online guessing.
  • com.openexchange.scim.allowUnauthenticatedDiscovery defines whether the discovery endpoints /ServiceProviderConfig, /ResourceTypes and /Schemas answer a caller that presents no credential. They describe the protocol, not the context, and identity providers read them before they authenticate. It defaults to true; a credential that is presented is checked either way, and false requires one for discovery as well.

No operator action is required by default.

SCR-1900

Summary: New lean configuration property com.openexchange.push.dovecot.unregisterOnMissingSession

Effective: 8.54.320 and later

In order to keep Dovecot Push registrations from piling up for users whose session has ended, the new lean configuration property com.openexchange.push.dovecot.unregisterOnMissingSession is introduced. When Dovecot notifies about a new message for a user for which no session can be resolved, the middleware drops that user's push registration through DoveAdm. It defaults to true, is reloadable and not config-cascade aware.

The registration is kept if it may still be wanted, that is if a permanent push listener or push notification subscriptions exist for that user. A configured DoveAdm end-point (com.openexchange.dovecot.doveadm.endpoints) is required; without one no registration is dropped. Set the property to false to restore the previous behavior.

See the property documentation for further details.

SCR-1892

Summary: New configuration option for caching the master administrator's password verification on provisioning calls

Effective: 8.54.320 and later

Provisioning calls are session-less and verify the master administrator's password against mpasswd on every call; with the default BCRYPT hash that costs about 100 ms of CPU per call and caps the master-level throughput. A successful verification is now remembered per node for a configurable time, so that further calls with the same credentials skip the password hash. Only a keyed hash of the password under a random per-node key is kept in memory; a wrong password always pays the full check, and reloading mpasswd with a changed hash invalidates the remembered verification. In addition, the duration of administrator authentication is exposed as Micrometer timer appsuite.provisioning.auth.duration with tags mode (master or context) and status.

  • com.openexchange.admin.masterPasswordVerificationTtlSeconds Specifies how long (in seconds) a successful verification of the master administrator's password is remembered on a node. A value less than or equal to 0 (zero) disables the cache and verifies the password hash on every call. Default 300. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-1884

Summary: New configuration options for remote Redis sites

Effective: 8.54.320 and later

Options for using remote Redis sites for cache invalidation, e.g. between two middleware clusters attached to one config database.

  • com.openexchange.redis.sites.scope What the configured remote sites are used for. all: sessions are replicated to the remote sites and looked up there, and cache invalidations are repeated there. invalidation: cache invalidations only; the sessiond sees no remote sites, so sessions stay on their site. Use invalidation for clusters that merely share the databases. Default all. Not reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.[site].cache.enabled Whether the remote site denoted by [site] (one of the identifiers listed in com.openexchange.redis.sites) runs a dedicated Redis instance for cache data. If enabled, that instance is configured through the [site].cache infix, e.g. com.openexchange.redis.[site].cache.hosts, and cache invalidations are repeated there; otherwise they are repeated on the remote site's regular Redis instance. Default false. Not reloadable, not config-cascade aware. File: redis.properties.

SCR-1879

Summary: New properties "vacation.internal.enabled" and "vacation.internal.externalTagHeader" for vacation notices treating internal and external senders differently

Effective: 8.54.320 and later

Two new lean configuration properties control the extended (internal/external) vacation rules of the accompanying HTTP-API SCR. Both are reloadable and config-cascade aware; the feature ships dark and requires an explicit operator opt-in:

  • com.openexchange.mail.filter.options.vacation.internal.enabled — the feature toggle, defaults to false.

  • com.openexchange.mail.filter.options.vacation.internal.externalTagHeader — the name of the classifier header the mail platform stamps on every delivered message (e.g. Vacation-External), defaults to empty; configuring it is a prerequisite. The values are fixed convention: true marks the sender external, false internal. A message carrying neither value — or both — receives no vacation notice at all: broken or missing stamping fails closed instead of leaking the internal text to external senders.

The mail platform MUST delete inbound instances of the classifier header before stamping, on every delivery path without exception. Before enabling, verify the stamping end to end following the recipe in the feature documentation: a message injected from an external sender with a forged header instance must arrive carrying the genuine external stamp instead — proving both deleting and stamping — on every delivery path (MX, internal delivery, forwards, list expansion). Do not enable the feature before every node in the cluster runs 8.54 or later, and only once a rollback below 8.54 is no longer expected: an older middleware keeps delivery working but edits extended rules unsafely, and any script write from a pre-8.54 node — saving or deleting any rule, not only vacation notices — temporarily splits an extended rule's branches in the middleware's rule model (delivery is unaffected; an 8.54 middleware reattaches the branches on the next read). The security contract, a stamping recipe, and the operator runbook including the downgrade behavior are described in the feature documentation; see the property documentation for the full property descriptions.

SCR-1877

Summary: New configuration option for contact auto-complete result limiting

Effective: 8.54.320 and later

In order to bound the size of a contact auto-complete response, a new lean configuration property is introduced for the contacts module.

  • com.openexchange.contact.autocomplete.maxResults Defines the maximum number of contacts returned by an addressbooks?action=autocomplete request that does not supply a right_hand_limit of its own. Such a request previously returned every matching contact, so a query of one or two characters could read and transfer a large part of the address book. A value of 0 (zero) or less disables the limit. Default 100. Reloadable, config-cascade aware. File: contact.properties.

Related change in the same area: a client-supplied right_hand_limit is now applied to auto-complete requests for every sort order. It was previously discarded whenever sort was omitted or set to one of the special sort orders, which are the ones App Suite uses for contacts.

SCR-1876

Summary: New configuration option for the virtual CalDAV collection "All my public appointments"

Effective: 8.54.320 and later

A new configuration option enables the virtual CalDAV collection All my public appointments, which exposes all appointments the user attends in public calendars as an additional calendar, without having to synchronize whole public calendars. Appointments can neither be created nor deleted through the collection, but the own participation status and alarms of existing appointments can be changed. The collection is only offered to users with access to public folders.

  • com.openexchange.caldav.allPublicEvents.enabled Enables the virtual All my public appointments collection via CalDAV. Default false. Reloadable, config-cascade aware. File: caldav.properties.

SCR-1868

Summary: Changed the custom fields syntax in logback.xml

Effective: 8.54.320 and later

Custom fields for the JSON and Logstash encoders are now declared with nested <name> and <value> elements inside <customField>. The previous attribute form, together with the <newRule> declaration for com.openexchange.logback.extensions.encoders.CustomFieldAction, silently stopped working when logback removed support for <newRule> in version 1.3, so no custom field has been written since. Administrators using custom fields have to rewrite those entries in logback.xml and can drop the <newRule> line; an incomplete field is now reported as a warning on the appender.

<appender name="LOGSTASH" class="com.openexchange.logback.extensions.appenders.logstash.LogstashAppender">
    <encoder class="com.openexchange.logback.extensions.encoders.JSONEncoder">
        <customField><name>deployment</name><value>production</value></customField>
        <customField><name>cluster</name><value>eu-1</value></customField>
    </encoder>
</appender>

SCR-1862

Summary: Renamed misspelled property com.openexchange.mail.prependReplyPrefx to com.openexchange.mail.prependReplyPrefix

Effective: 8.54.320 and later

The property com.openexchange.mail.prependReplyPrefx - which controls whether the reply prefix (e.g. Re:) is prepended to the unquoted reply text instead of being included in the quoted text - was misspelled. It is now named com.openexchange.mail.prependReplyPrefix. It defaults to false and is neither reloadable nor config-cascade aware.

No operator action is required: the misspelled name is still evaluated as a fallback, so an existing configuration keeps working. It is deprecated and logs a warning once when it takes effect; deployments that set it should move to the corrected name.

See the property documentation for further details.

SCR-1857

Summary: New properties for the OpenCloud file storage

Effective: 8.54.320 and later

The following properties are introduced for the file storage service opencloud. All of them are reloadable, and all but com.openexchange.file.storage.opencloud.entityResolver.attribute and com.openexchange.file.storage.opencloud.entityResolver.mappingFile are config-cascade aware, so a deployment may integrate a different OpenCloud instance per context or user.

  • com.openexchange.capability.filestorage_opencloud enables the storage for a user. It defaults to false.
  • com.openexchange.file.storage.opencloud.entityResolver.attribute states the attribute the users of an instance are matched with the ones of the server by, either mail or username. It defaults to mail.
  • com.openexchange.file.storage.opencloud.entityResolver.mappingFile states the path to a file mapping the users and groups of an instance to the ones of the server statically, which takes precedence over matching them by an attribute. It is empty by default.
  • com.openexchange.file.storage.opencloud.entityResolver.folderPermissions states whether the shares of a folder are expressed as its permissions, which requires a request per folder. It defaults to false.
  • com.openexchange.file.storage.opencloud.entityResolver.objectPermissions states whether the shares of a file are expressed as its object permissions. It defaults to false.
  • com.openexchange.file.storage.opencloud.entityResolver.createdModifiedBy states whether the users that created and modified an item are looked up within the instance. It defaults to true, and states the session's user otherwise.
  • com.openexchange.oauth.opencloud.hostname states the host of the instance the deployment integrates with. It is empty by default and required if com.openexchange.oauth.opencloud.enabled is set to true.
  • com.openexchange.oauth.opencloud.authorizationUrl states the URL the user is directed to in order to authorize the deployment. It is empty by default, which uses the endpoint of the identity provider built into OpenCloud.
  • com.openexchange.oauth.opencloud.tokenUrl states the URL an authorization code and a refresh token are redeemed at. It is empty by default, which uses the endpoint of the identity provider built into OpenCloud.
  • com.openexchange.oauth.opencloud.userInfoUrl states the URL the identity of the user is read from. It is empty by default, which uses the endpoint of the identity provider built into OpenCloud.
  • com.openexchange.oauth.opencloud.scope states the scopes that are requested when the deployment is authorized, separated by spaces. It defaults to openid profile email offline_access.

OAuth is configured through the properties of an OAuth service with the service identifier opencloud, so com.openexchange.oauth.opencloud.enabled, apiKey, apiSecret, redirectUrl and productName. An instance that is fronted by an identity provider of its own, e.g. Keycloak, states its endpoints through the properties above. A public client that authenticates with PKCE states no apiSecret. Such an instance associates a token with one of its users by the claims the token states, e.g. the roles or the groups of that user, so the client the deployment is authorized with needs to state the same claims as the client of the instance itself, which may require a further scope.

See the property documentation for further details.

SCR-1854

Summary: New property com.openexchange.calendar.useNoReplyAddressForNotifications

Effective: 8.54.320 and later

In order to let deployments whose no-reply relay is not authorized for the users' mail domains pass SPF and DMARC checks, the new lean configuration property com.openexchange.calendar.useNoReplyAddressForNotifications is introduced. If enabled, the configured no-reply address replaces the From header of calendar notification mails to internal recipients that are transported via the no-reply account, and the Sender and Reply-To headers are dropped. It defaults to false, is reloadable and config-cascade aware.

External iMIP messages are never affected, as their From header has to stay aligned with the ORGANIZER property. Note that the property keys on the recipient being internal, not on the message kind: with com.openexchange.calendar.useIMipForInternalUsers enabled, internal users receive full iMIP messages and those are rewritten as well, which RFC-conformant calendar clients may reject. Enable both only if internal recipients read their invitations in App Suite.

It applies wherever the no-reply account is used, which is not limited to com.openexchange.calendar.preferNoReplyForNotifications: guests, users without webmail permission, restricted sessions and impersonation sessions take that account on their own, so mails triggered by them change as well. The value is evaluated for the acting user, not for the organizer. No operator action is required by default. See the property documentation for further details.

Database

SCR-1987

Summary: Added the "xctx_grants" Cross-Context Grant Index Table and Create-Table Update Task

Effective: 8.54.320 and later

Update Task

New per-context table xctx_grants in the resource owner's context user schema - the mirror of xctx_liaisons, one small row per foreign context holding access on a resource of this context.

CREATE TABLE xctx_grants (
  `cid` INT4 UNSIGNED NOT NULL,
  `entity` INT4 UNSIGNED NOT NULL,
  `module` INT4 UNSIGNED NOT NULL DEFAULT 0,
  `grantee_cid` INT4 UNSIGNED NOT NULL,
  `type` INT4 UNSIGNED NOT NULL DEFAULT 0,
  PRIMARY KEY (`cid`, `entity`, `module`, `grantee_cid`, `type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

cid/entity = owner context + resource owner; grantee_cid = the foreign context holding access; type = LiaisonType (3 = SHARED_ACCOUNT). A shared account permission is stored in the grantee's context, so the account's own context has no record of it - this index is what makes it answerable.

  • Fresh schemas: com.openexchange.crosscontext.impl.storage.rdb.groupware.CrossContextGrantsCreateTableService
  • Existing schemas: com.openexchange.crosscontext.impl.storage.rdb.groupware.CrossContextGrantsCreateTableTask (UpdateTaskAdapter, no dependencies, idempotent)
  • Cleanup and backfill: CrossContextGrantsDeleteListener plus the DatabaseCleanUpService jobs SharedAccountGrantsSourceCleanUpExecution and GrantsCleanUpExecution (1/day each)

The source-side job backfills grants issued before the index existed. It skips any schema with a pending update task, so on an upgraded system the index completes once those updates have run.

See the feature documentation for further details.

SCR-1952

Summary: New tables mail_credential and mail_credential_migration

Effective: 8.54.320 and later

Update Task

The two new tables mail_credential and mail_credential_migration in every context schema belong to the mail credential vault: the first keeps the encrypted mail credentials, the second how far the clean-up job that moves credentials of the old format into the vault has come. Both are added by the update task com.openexchange.mail.credential.impl.groupware.MailCredentialCreateTableTask. Expired rows of mail_credential are dropped hourly by a database clean-up job; rows of deleted users and contexts are dropped with them. A table whose credentials have all been moved carries a non-zero finished in mail_credential_migration. No admin action.

Table layout:

CREATE TABLE mail_credential (
  `cid` INT4 UNSIGNED NOT NULL,
  `id` BINARY(16) NOT NULL,
  `user` INT4 UNSIGNED NOT NULL,
  `feature` VARCHAR(64) NOT NULL,
  `kind` VARCHAR(16) NOT NULL,
  `caller_key` TINYINT(1) NOT NULL DEFAULT 0,
  `login` VARCHAR(255) DEFAULT NULL,
  `ciphertext` TEXT DEFAULT NULL,
  `created` BIGINT(20) NOT NULL,
  `expires` BIGINT(20) NOT NULL DEFAULT 0,
  `version` INT4 NOT NULL DEFAULT 1,
  `lease` BIGINT(20) NOT NULL DEFAULT 0,
  PRIMARY KEY (`cid`,`id`),
  KEY `user` (`cid`,`user`,`feature`,`created`),
  KEY `expires` (`expires`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE mail_credential_migration (
  `table_name` VARCHAR(64) NOT NULL,
  `resume_at` BINARY(16) DEFAULT NULL,
  `finished` BIGINT(20) NOT NULL DEFAULT 0,
  PRIMARY KEY (`table_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

SCR-1947

Summary: New table access_token in the context database schema

Effective: 8.54.320 and later

Update Task

Personal access tokens are stored in the new table access_token of the context database schema, created for new schemas by the create-table service and for existing ones by the update task com.openexchange.accesstoken.impl.groupware.AccessTokenCreateTableTask: columns cid, id (BINARY(16)), user, hash (the SHA-256 hash of the secret; the secret itself is never stored), label, scopes, created, expires, last_used and credential (BINARY(16), the identifier of the row in mail_credential the mail credential vault keeps for the token, sealed with the token's secret; NULL when nothing is kept), with primary key (cid, id), unique key (cid, hash) and key (cid, user). Rows are removed together with their user or context; the vault row goes with the token when it is revoked or expires. No admin action beyond the usual update task run.

SCR-1922

Summary: New column softDeleted in the user tables

Effective: 8.54.320 and later

Update Task

The tables user and del_user of every context schema receive the nullable column softDeleted (BIGINT(64)), the time a user has been soft-deleted in milliseconds since the epoch, together with the index softDeletedIndex on user. New schemas receive the column with the table, existing schemas through the update task. Existing rows keep NULL, no data is migrated.

ALTER TABLE user ADD COLUMN softDeleted BIGINT(64) DEFAULT NULL;
ALTER TABLE user ADD INDEX softDeletedIndex (softDeleted);
ALTER TABLE del_user ADD COLUMN softDeleted BIGINT(64) DEFAULT NULL;

SCR-1903

Summary: New table scim_external_id in the context schema

Effective: 8.54.320 and later

Update Task

The SCIM service provider stores the externalId an identity provider assigns to a resource - a user, group, resource, shared account, deputy or secondary account - in the new table scim_external_id of every context schema, unique per context and resource type and compared case-sensitively. The identifier of the resource is kept as text, since deputies and secondary accounts have none that is a number. New schemas receive the table from ScimStorageCreateTableService, existing schemas through the update task ScimStorageCreateTableTask, and a schema that received the table with a numeric id before is converted by ScimExternalIdTextKeyTask; the bundle com.openexchange.scim.storage ships with open-xchange-core so that every node knows the table. It starts empty, no data is migrated, and rows are removed with their user or context.

CREATE TABLE scim_external_id (
  cid INT4 UNSIGNED NOT NULL,
  type TINYINT UNSIGNED NOT NULL,
  id VARCHAR(191) NOT NULL,
  external_id VARCHAR(255) NOT NULL,
  PRIMARY KEY (cid, type, id),
  UNIQUE KEY external_id (cid, type, external_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

SCR-1898

Summary: New tables provisioning_token in the context schema and crosscontext_provisioning_token in the configdb

Effective: 8.54.320 and later

Update Task

Provisioning tokens bound to a context are stored in the new table provisioning_token of every context schema. New schemas receive it from ProvisioningTokenCreateTableService, existing schemas through the update task. The table holds the SHA-256 hash of a secret together with label, scope, creator and the creation, expiration and last-use times. It starts empty, no data is migrated.

CREATE TABLE provisioning_token (
  cid INT4 UNSIGNED NOT NULL,
  id BINARY(16) NOT NULL,
  hash VARCHAR(64) NOT NULL,
  label VARCHAR(128) NOT NULL,
  scope VARCHAR(32) NOT NULL,
  created_by VARCHAR(191) NOT NULL,
  created BIGINT(20) NOT NULL,
  expires BIGINT(20) NOT NULL DEFAULT 0,
  last_used BIGINT(20) NOT NULL DEFAULT 0,
  PRIMARY KEY (cid, id),
  UNIQUE KEY hash (cid, hash)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

Cross-context tokens, which open several contexts at once, live in the configuration database: the token in the new table crosscontext_provisioning_token, one row per context it opens in crosscontext_provisioning_token_context. Both are created at start-up, each by its own change set of configdbChangeLog.xml - 8:crosscontext_provisioning_token:create and 8:crosscontext_provisioning_token_context:create - so no manual step is needed; they start empty as well. Deleting a context removes its rows from crosscontext_provisioning_token_context, and a token left with no context is deleted along with it.

CREATE TABLE crosscontext_provisioning_token (
  id BINARY(16) NOT NULL,
  hash VARCHAR(64) NOT NULL,
  label VARCHAR(128) NOT NULL,
  scope VARCHAR(32) NOT NULL,
  created_by VARCHAR(191) NOT NULL,
  created BIGINT(20) NOT NULL,
  expires BIGINT(20) NOT NULL DEFAULT 0,
  last_used BIGINT(20) NOT NULL DEFAULT 0,
  PRIMARY KEY (id),
  UNIQUE KEY hash (hash)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE crosscontext_provisioning_token_context (
  token BINARY(16) NOT NULL,
  cid INT4 UNSIGNED NOT NULL,
  PRIMARY KEY (token, cid),
  KEY cid (cid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

SCR-1890

Summary: New Column classifiedAccess in Table deputy for the Calendar Deputy Right to See Confidential Appointments

Effective: 8.54.320 and later

Update Task

In order to persist the new right of a calendar deputy to see the granting user's confidential appointments with the deputy permission itself (rather than in folder metadata a folder administrator could tamper with), the table deputy gained the column classifiedAccess next to sendOnBehalfOf, holding the granted level as numerical identifier (0 for none, 1 for confidential).

ALTER TABLE deputy ADD COLUMN classifiedAccess TINYINT UNSIGNED NOT NULL DEFAULT 0;

The update task adds the column to existing schemas, fresh schemas get it through the create table service. Existing rows keep the default 0, so no deputy gains the right implicitly and no operator action is required. The column is read by the calendar only when a deputy encounters a classified appointment in a shared calendar folder carrying deputy permissions, through the deputy service's storage-only listing of the grants the folder owner made to the deputy.

SCR-1853

Summary: New table deputy_mail_acl_baseline holding the mail ACL baseline of a deputy permission

Effective: 8.54.320 and later

Update Task com.openexchange.deputy.provider.imap.groupware.DeputyMailAclBaselineCreateTableTask

In order to record a deputy permission's mail ACL baseline reliably, the mailboxes on which the deputy already held an ACL before the permission was granted are now kept in the new table deputy_mail_acl_baseline instead of in the granting user's INBOX metadata entry /shared/vendor/vendor.open-xchange/deputydir-<deputyId>.

The baseline is now recorded once, at the first grant. It was previously re-captured on every grant, so a mailbox outside the permission's folder list that had only received its ACL through the grant itself, typically a subfolder Dovecot inherits from INBOX, counted as pre-existing and kept the deputy's ACL when the permission was revoked.

CREATE TABLE deputy_mail_acl_baseline (
  cid INT4 UNSIGNED NOT NULL,
  uuid BINARY(16) NOT NULL,
  user INT4 UNSIGNED NOT NULL,
  account INT4 UNSIGNED NOT NULL DEFAULT 0,
  fullname VARCHAR(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  rights VARCHAR(32) CHARACTER SET latin1 NOT NULL DEFAULT '',
  PRIMARY KEY (cid, uuid, account, fullname),
  KEY userId (cid, user)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

Deputy permissions granted before this change are not migrated; their baseline is still read from the metadata entry, and both locations are cleared when the permission is revoked. The update task only creates the table and does not touch existing rows. No operator action is required.

Packaging/Bundles

SCR-1999

Summary: New bundle com.openexchange.mail.messageid.redis for the folder rename history of the Mobile API

Effective: 8.54.320 and later

The package open-xchange-core ships the new bundle com.openexchange.mail.messageid.redis. It keeps a 30-day history of mail folders renamed or moved through App Suite in Redis, one hash ox-mail-folder-renames:<context>:<user>:<account> per mail account, so that Mobile API clients can recognize renamed folders on mail servers whose folder identifiers depend on the name (not Dovecot). Entries are written only for users with com.openexchange.mobile.api.enabled; updates use a Lua script unless com.openexchange.redis.lua.enabled is false. No admin action.

SCR-1997

Summary: New package open-xchange-mobile-api and Helm feature mobile-api

Effective: 8.54.320 and later

The new package open-xchange-mobile-api ships the bundle com.openexchange.mobile.api, which serves the Mobile API at /mobile/v1. It requires open-xchange-core and open-xchange-oauth-provider.

The core-mw Helm chart keeps the package switched off through the new feature mobile-api, like mcp. Both switches are needed: the feature starts the bundle, com.openexchange.mobile.api.enabled lets it answer.

SCR-1979

Summary: New bundle com.openexchange.pns.transport.sse

Effective: 8.54.320 and later

Added the new bundle com.openexchange.pns.transport.sse to the open-xchange-pns-impl package. It provides the push notification transport sse, which delivers notifications to live change streams (Server-Sent Events) and shares the presence of open streams among the nodes via Redis. The transport is disabled by default, see com.openexchange.pns.transport.sse.enabled.

SCR-1953

Summary: New bundles for WebDAV-Push: com.openexchange.dav.push and com.openexchange.pns.transport.webpush

Effective: 8.54.320 and later

The package open-xchange-pns-impl gains the bundle com.openexchange.pns.transport.webpush: a push notification service transport with id webpush that delivers RFC 8291 encrypted Web Push messages with RFC 8292 VAPID authorization to arbitrary push services (UnifiedPush distributors, FCM Web Push endpoints). It exports com.openexchange.pns.transport.webpush.WebPushService and the packages ...webpush.crypto and ...webpush.vapid, registers the managed HTTP client webpush, and imports com.openexchange.keystore from open-xchange-core to read the VAPID key from a Kubernetes secret. Public key derivation uses the BouncyCastle bundles already on the platform; no new third-party library.

The package open-xchange-dav gains the bundle com.openexchange.dav.push: WebDAV-Push (draft-bitfire-webdav-push-00, as used by DAVx5) for CalDAV and CardDAV. It contributes the transports, topic and supported-triggers property mixins, the push-register handling, the registration servlet below /push, the calendar, contact and task handlers that turn changes into notifications for the client webdav-push, and the push-message generator. It plugs into the DAV stack via the new SPI com.openexchange.dav.DAVPushService exported by com.openexchange.dav, which additionally gained the webdav-push DAV header option, the POST hook and the Push-Dont-Notify header handling. Because the bundle uses the transport's service, open-xchange-dav now depends on open-xchange-pns-impl.

Both bundles start with their packages and stay inert until configured: no VAPID key means no transport, and com.openexchange.dav.push.enabled defaults to false. No Helm chart change (the secret uses the existing OX_KEYSTORE mechanism), no database change (regular push notification service subscriptions), no admin action unless push for DAVx5 is wanted.

See the general documentation for further details.

SCR-1949

Summary: New package open-xchange-mcp with the bundles of the MCP server

Effective: 8.54.320 and later

The new package open-xchange-mcp contains the bundles com.openexchange.mcp (MCP endpoint, prompts, me_get), com.openexchange.mcp.contacts (contacts_search, contact_get, users_search), com.openexchange.mcp.mail (mail_search, mail_get, mail_attachment_get, mail resources), com.openexchange.mcp.calendar (calendar_list_events, calendar_get_event, calendar_free_busy, resources_search), com.openexchange.mcp.files (files_search, file_get, file resources), com.openexchange.mcp.tasks (tasks_search, task_get), com.openexchange.mcp.vacation (vacation_get) and com.openexchange.mcp.reminders (reminders_list); each module bundle also registers its folder tool. com.openexchange.mcp exports the service interfaces com.openexchange.mcp.tools.McpTool and com.openexchange.mcp.resources.McpResource, so further bundles can contribute tools and resources. The package depends on open-xchange-core, which ships the personal access tokens the endpoint accepts (SCR-1946). The Helm chart core-mw knows it as the feature mcp (features.definitions.mcp), which is disabled by default in features.status, so the bundles are not started unless an operator enables the feature; the endpoint additionally needs com.openexchange.mcp.enabled=true. No admin action unless the MCP server is wanted.

SCR-1916

Summary: New package open-xchange-admin-soap-common required by the administrative SOAP packages

Effective: 8.54.320 and later

The administrative SOAP bundles each carried their own copy of the same XML types. Those shared types now live in the new bundle com.openexchange.admin.soap.common, shipped in the new package open-xchange-admin-soap-common.

The following packages now depend on it, so it is pulled in automatically on upgrade and no operator action is required:

  • open-xchange-admin-soap
  • open-xchange-admin-soap-reseller
  • open-xchange-admin-soap-usercopy

No published WSDL changes: every copy already used the same XML namespace and the same content model, so the consolidation is not visible on the wire. Existing SOAP clients are unaffected.

SCR-1904

Summary: Added package open-xchange-scim and the chart feature scim

Effective: 8.54.320 and later

The SCIM service provider is packaged as follows.

  • New package open-xchange-scim with the bundle com.openexchange.scim; it depends on open-xchange-core and open-xchange-admin.
  • New bundle com.openexchange.scim.storage in open-xchange-core, carrying the table, its update task and the delete listener.
  • New chart feature scim in helm/core-mw (features.definitions.scim = open-xchange-scim), disabled globally and enabled on the admin role by default through roles.admin.values.features.status.scim, so the endpoint runs on the admin pods only. Set it to disabled there to switch the endpoint off.

SCR-1855

Summary: New bundles for OpenCloud and Nextcloud and new dependency of open-xchange-file-storage-webdav on open-xchange-oauth

Effective: 8.54.320 and later

The file storage service opencloud and refactoring of existing file storage service nextcloud ships with two new bundles.

  • com.openexchange.opencloud, the generated client of the libre graph API, within the package open-xchange-file-storage-webdav
  • com.openexchange.oauth.opencloud, the OAuth provider of an OpenCloud instance, within the package open-xchange-oauth
  • com.openexchange.oauth.nextcloud, the OAuth provider of an Nextcloud instance, within the package open-xchange-oauth

The OpenCloud and Nextcloud storages require the package open-xchange-oauth to be enabled, no matter whether an account authenticates with a username and an app token or through OAuth, as they are not registered at all otherwise.

8.53.217

General

SCR-1848

Summary: New thread pool saturation metrics

Effective: 8.53.217 and later

The platform thread pool exposes two new counters at the /metrics endpoint: appsuite_executor_saturated_total counts task submissions that found the pool already grown to its maximum size, and appsuite_executor_refused_total counts tasks that could neither be run nor be queued and were therefore handed to com.openexchange.threadpool.refusedExecutionBehavior. Both carry the tag name="main" and complement the existing appsuite_executor_queued gauge, which only reports the queue depth at scrape time. They are absent unless the pool uses a scaling work queue.

SCR-1822

Summary: Added command-line tool threaddump that covers virtual threads

Effective: 8.53.217 and later

The new command-line tool threaddump writes a thread dump of the middleware that includes virtual threads. The middleware runs its HTTP work on virtual threads, which neither jstack nor the Thread.print diagnostic command lists. It therefore uses Thread.dump_to_file through JMX, which needs no jcmd binary - the runtime image ships none. The middleware writes the file itself, so the path given via -f is resolved on the middleware's host. That dump performs no deadlock analysis, hence --print-classic prints the classic dump as a second, separate dump on the terminal. Further options are --format (plain or json, where json carries no lock information) and --overwrite.

$ threaddump -f /tmp/threads.txt
Thread dump successfully written to file /tmp/threads.txt on the middleware's host

$ head /tmp/threads.txt
7
2026-08-14T06:54:19.525073364Z
25.0.4+-wolfi-r0

#3 "main" RUNNABLE 2026-08-14T06:54:19.525200Z
    at ...

#28 "OXWorker-0007" virtual BLOCKED 2026-08-14T06:54:19.525300Z
    at ...
    - waiting to lock <java.lang.Object@2df9b86>

API - HTTP-API

SCR-1844

Summary: New deputy module action reverseIds that lists the granting users without resolving grant details

Effective: 8.53.217 and later

The deputy module gained the action GET /ajax/deputy?action=reverseIds, a light-weight counterpart to action=reverse. It lists the users that appointed the requesting user as their deputy, but resolves neither the granted folders nor the permission bits. Resolving those requires consulting every module involved; for the mail module that is a server-wide GETMETADATA sweep per mail account, whose cost grows with the number of mailboxes visible to the user. This action is answered from the deputy storage alone.

Each element of the returned array carries:

  • grantorId - the identifier of the granting user, or 0 for a cross-context grantor whose bare identifier has no meaning in the requesting user's context
  • grantorIdentifier - the qualified identifier as <userId>@<contextId>
  • grantorEntityInfo - pre-resolved entity information for rendering the grantor
  • deputyIds - the identifiers of the deputy permissions this user granted
  • sendOnBehalfOf - whether at least one of those grants permits sending on the granting user's behalf, aggregated across that user's grants because the addresses belong to the granter rather than to an individual grant
  • grantorAddresses - the addresses to send from, present only when sendOnBehalfOf is true; the full listing applies the same gate

Example request:

GET /ajax/deputy?action=reverseIds&session=<session-id>

Example response:

{
  "data": [
    {
      "grantorId": 3,
      "grantorIdentifier": "3@1",
      "grantorEntityInfo": {
        "identifier": "3@1",
        "type": "user",
        "display_name": "Jane Doe",
        "entity": 3,
        "contact": {
          "first_name": "Jane",
          "last_name": "Doe",
          "email1": "jane.doe@example.org"
        }
      },
      "deputyIds": [
        "a3fff8061eae4078817533438c090a9b",
        "0c1d7f52a1b04e6f9d2c8e3b5a7f1042"
      ],
      "sendOnBehalfOf": true,
      "grantorAddresses": [
        "jane.doe@example.org",
        "j.doe@example.org"
      ]
    }
  ]
}

Purely additive: action=reverse is unchanged. Note that an orphaned grant, one whose module no longer backs a permission, is still listed by action=reverseIds - detecting and removing it is what the full listing does when it consults the modules.

On 8.51 and 8.50 the action is available in a reduced form: sendOnBehalfOf and grantorAddresses are present, but grantorIdentifier and grantorEntityInfo are not - those lines do not carry the qualified grantor identity internally. A client that has to work across all four lines should key on grantorId there.

SCR-1818

Summary: New HTTP API action mail?action=emlToken to download a message as .eml file without a session

Effective: 8.53.217 and later

In order to let a message be handed to software outside App Suite - dragging a mail onto Windows Explorer, a DMS or an electronic file - the new action mail?action=emlToken issues a token that allows to download the complete message in MIME format through /ajax/mail.attachment?id=<token> without a session and without cookies. The resulting URL grants access to that message including all headers and attachments and is therefore to be treated like a credential.

  • folder and id identify the message and are mandatory.
  • ttlMillis shortens the token's lifetime; a value above the configured default is capped to it.
  • oneTime invalidates the token once it has been redeemed, default false.
  • checkIp restricts the download to the client address the token was issued for, default false.

Example:

GET /ajax/mail?action=emlToken&folder=default0/INBOX&id=42&session=<session>
{"data":{"id":"eml-25d14828e3a44238abf25e954a35eefa.e8dd9dfbe4e54f8d8e2c0d49ae4999e6","jsessionid":null}}
GET /ajax/mail.attachment?id=eml-25d14828e3a44238abf25e954a35eefa.e8dd9dfbe4e54f8d8e2c0d49ae4999e6

The download is answered as application/octet-stream with a file name derived from the message's subject. It is streamed, hence it carries no Content-Length and byte ranges are not served - a range request is answered in full. HEAD is rejected with 405. The token's lifetime is fixed and does not slide; only the start of the download has to fall into it, a running download is not cut off. Its default is configured through com.openexchange.mail.emlToken.ttl.

The change is purely additive for existing clients. The pre-existing action mail?action=attachmentToken is now documented as well; its ttlMillis parameter remains without effect.

API - Java

SCR-1832

Summary: Relocated configuration and user-configuration Java packages

Effective: 8.53.217 and later

Custom bundles and plugins that use the configuration API must be adapted:

  • com.openexchange.config.ConfigurationService, Reloadable, Interests, PropertyFilter and related types moved to the com.openexchange.config.common package and bundle; import statements and bundle manifests must be repointed.
  • The UserConfiguration API moved to com.openexchange.config.universal; ServerSession.getUserConfiguration() now returns UserConfigurationImpl.

Code compiles against the old manifest imports but fails at OSGi resolution, so the manifest change is mandatory. The OX-maintained plugin repositories are adapted in the same release train.

Behavioral Changes

SCR-1850

Summary: Changed reporting of long-running tasks by the thread pool's active-task watcher

Effective: 8.53.217 and later

The thread pool's active-task watcher changed how it reports tasks that exceed com.openexchange.requestwatcher.maxRequestAge.

  • Each report is now prefixed with a per-task sighting counter, as the request watcher already does: #3 Worker thread with age 8,339ms (8s 339ms) exceeds max. age of 2,000ms (2s). Log processing that matches on the previous message text still matches, but the leading counter is new. A jump in that counter shows that reporting was throttled in between.

  • Reporting is no longer unconditional. Above com.openexchange.threadpool.watcher.reportBackoffThreshold concurrently long-running tasks the watcher doubles the interval between reports instead of capturing a stack trace for every task on every scan. Skipped scans emit a single summary line. Below the threshold nothing changes.

  • The watcher can now interrupt a long-running task and eventually give up on it, which is off by default and enabled with com.openexchange.threadpool.watcher.interruptTasks. Unlike the request watcher, the task's age is the only interrupt trigger; the session is deliberately not consulted, since that look-up may reach the session storage and a stalled storage would block the very scan meant to report the stall.

SCR-1847

Summary: Changed behavior of the thread pool saturation settings

Effective: 8.53.217 and later

The thread pool settings com.openexchange.threadpool.blocking and com.openexchange.threadpool.refusedExecutionBehavior had no effect with the default scaling pool, where tasks queued without bound once all worker threads were busy. They now apply as documented as soon as com.openexchange.threadpool.workQueueSize is set to a positive value. With its default of 0 the work queue stays unbounded and nothing changes, except that the effective saturation semantics are now logged once at start-up, with a warning if either setting was configured but cannot apply. Deployments that already combine blocking with a bounded work queue will see submitting threads actually wait for queue space from now on. Independently of the configuration, a task refused by a saturated or shut-down pool no longer leaves its future pending forever, and a task submitted with an individual refused-execution behavior is no longer handled twice.

SCR-1840

Summary: New JMX bean for the timer executor and spill-over volume in its warning

Effective: 8.53.217 and later

The executor that runs timer tasks is now readable over JMX as com.openexchange.threadpool:name=TimerThreadPoolInformation, reporting the same attributes as the existing VirtualThreadPoolInformation bean: maximum concurrency, active tasks, available permits, waiting submitters and the submitted, completed and rejected counts. It is registered only while the timer executor exists, so it is absent when com.openexchange.threadpool.timer.maxConcurrency is set to 0. This is the way to read those numbers on installations that do not scrape the appsuite.executor.timer.* meters. In addition, the warning logged when due timer tasks spill over to the platform thread pool now states how many did so since the previous warning and since node start, taken from the same counter the appsuite.executor.timer.rejected meter reports. No configuration change and no admin action.

SCR-1837

Summary: Changed timer tasks to run on virtual threads instead of the platform thread pool

Effective: 8.53.217 and later

Timer tasks scheduled through the TimerService (schedule, scheduleAtFixedRate, scheduleWithFixedDelay) execute on virtual threads named OXTimer-* instead of platform pool workers, so periodic housekeeping no longer competes with request processing for OXWorker-* threads. Scheduling, cancellation and the ScheduledFuture contract are unchanged. The number of concurrently executing timer tasks is bounded by com.openexchange.threadpool.timer.maxConcurrency (default 64); beyond that bound, due timer tasks spill over to the platform pool as before. New Micrometer meters appsuite.executor.timer.active, appsuite.executor.timer.concurrency.limit, appsuite.executor.timer.permits.available, appsuite.executor.timer.submitters.waiting, appsuite.executor.timer.submitted, appsuite.executor.timer.completed and appsuite.executor.timer.rejected mirror the existing appsuite.executor.virtual.* meters and are only registered while the timer executor is enabled. No admin action is required; setting the property to 0 restores the previous behavior.

SCR-1826

Summary: New metrics for the Redis circuit breakers and bulkhead

Effective: 8.53.217 and later

The Redis connector now reports Micrometer meters for its resilience policies: appsuite_redis_breaker_state (0 closed, 1 half-open, 2 open, -1 disabled; the breaker tag tells the two breakers apart - common guards against failing operations, connect against an unreachable end-point), appsuite_redis_breaker_rejected and appsuite_redis_bulkhead_rejected, counting the operations shed by the respective policy. The connection pool additionally reports appsuite_redis_connections_num_multiplexed, the number of operations currently using a connection. In the default shared pool mode operations are multiplexed onto a fixed number of connections, so appsuite_redis_connections_num_active is bounded by the configured pool size and borrowing never blocks - appsuite_redis_connections_num_waiters and the borrow wait times are always zero there. Saturation therefore shows as appsuite_redis_bulkhead_rejected rising and appsuite_redis_breaker_state leaving zero, not through the pool gauges; alerts built on the pool gauges should be revisited. No new configuration.

SCR-1821

Summary: Sending with a shared folder owner's address now requires an explicit permission

Effective: 8.53.217 and later

Access to another user's shared mail folder no longer implies permission to send with that user's address. Previously a reply or forward from a shared folder was composed with the folder owner's address as From and the sending user's as Sender, and the transport accepted such a message even when no deputy permission existed at all; the owner's address was used as envelope sender as well.

The folder owner's address is now only used when that user granted a deputy permission carrying "send on behalf of", or consented through the new property. Otherwise the sending user's own address is used, and a submitted message carrying a foreign From is rejected with MSG-0129.

  • com.openexchange.mail.allowSendOnBehalfOfByFolderOwnership Lets those who have access to a user's shared folders send with that user's address without a deputy permission. It is evaluated in the folder-owning user's scope rather than the sending user's. Default false. Reloadable, config-cascade aware. File: mail.properties.

The deprecated predecessor com.openexchange.mail.ignoreSendOnBehalfOfDetection is still honored where it withholds the privilege; an explicit false is no longer read as consent. Both keys are resolved in one walk over the config cascade, most specific scope first.

Deployments running role mailboxes that relied on the previous behavior need either a deputy permission carrying "send on behalf of" or the new property set on the mailbox user. Setting it at context or server scope is possible but means every user there lends their sender identity to anyone they share a folder with.

See the configuration documentation for further details.

SCR-1814

Summary: Reseller ownership and restrictions are now enforced when copying a user

Effective: 8.53.217 and later

With open-xchange-admin-reseller installed, the usercopy provisioning call now behaves like user creation: the calling administrator has to own both the source and the destination context, or be the parent of their owners, and a copied user counts against the restrictions of the destination context (Context.MaxUser, Subadmin.MaxOverallUser and their module access variants). Previously neither was checked, so any subadmin could copy any user between arbitrary contexts and copied users counted against no limit.

The restrictions are evaluated before the copy as a fast fail and again afterwards, which is the binding decision. Evaluating after the write is what keeps a limit from being exceeded when copies run in parallel, and it is the order user creation already uses. A rejected copy is removed again; copies issued in parallel against a context close to its limit may therefore all be rejected.

Copies performed by a subadmin require MASTER_ACCOUNT_OVERRIDE=true in AdminDaemon.properties, as every other user provisioning call performed by a subadmin does.

The check whether an administrator owns a set of contexts was corrected as well: it correlated database rows with the given contexts by position instead of by context identifier, and treated a context without an owner as owned. Such contexts remain reserved for the master administrator now.

Deployments without the reseller extension are not affected.

Changed defaults

SCR-1838

Summary: Changed defaults for the in-memory cache layer

Effective: 8.53.217 and later

The cache.v2 in-memory caching layer in front of Redis is now enabled by default with a shorter time-to-live. It removes the Redis round-trip from the request hot path (measured +31 % request throughput). Replicas are dropped on cache events and on the user, context and reseller invalidation channels; otherwise they expire after the time-to-live.

  • com.openexchange.cache.v2.redis.inmemory.enabled Whether to use the volatile in-memory cache as facade prior to accessing Redis storage. Default changed from false to true. Not reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.cache.v2.redis.inmemory.timeToLiveMillis The time-to-live of elements in the in-memory caching layer in volatile mode. Default changed from 10000 to 5000. Not reloadable, not config-cascade aware. File: redis.properties.

Compatibility: the deprecated com.openexchange.cache.v2.redis.useInMemoryCache is only consulted when com.openexchange.cache.v2.redis.inmemory.enabled yields false; an explicit useInMemoryCache=false therefore no longer disables the layer, an explicit inmemory.enabled=false still does. Deployments serving non-sticky clients (CalDAV/CardDAV) may want to disable the layer on those nodes, as documented.

Configuration

SCR-1849

Summary: New configuration options for the thread pool's active-task watcher

Effective: 8.53.217 and later

The thread pool's active-task watcher, which reports tasks that run longer than com.openexchange.requestwatcher.maxRequestAge, gained two configuration options.

  • com.openexchange.threadpool.watcher.interruptTasks Controls whether the watcher may interrupt a long-running task instead of only reporting it. A trackable task is one submitted from a request-processing thread that the request watcher already tracks, so it is then governed like its parent request: once it outlives com.openexchange.requestwatcher.expiredRequestAge, its thread is interrupted; if it survives that, it is reported once more after com.openexchange.requestwatcher.interruptedThreshold further sightings and then no longer reported. An expiration age below com.openexchange.requestwatcher.maxRequestAge is logged and disables expiration by age. Interrupting aborts work the calling request may still be waiting for, hence it is off by default. Default false. Not reloadable, not config-cascade aware. File: threadpool.properties.

  • com.openexchange.threadpool.watcher.reportBackoffThreshold The number of concurrently long-running tasks above which the watcher reports less often. Up to this many tasks every one of them is reported on every scan, at com.openexchange.requestwatcher.frequency. Above it the interval between reports doubles from report to report, up to every 32nd scan, and returns to every scan once the number falls back to the threshold. No task is ever dropped from reporting; only the frequency changes. This bounds what a stalled backend dependency costs, where thousands of tasks would otherwise yield thousands of foreign-thread stack traces on every scan. A value of 0 (zero) disables the backoff; it is also inactive while com.openexchange.threadpool.watcher.interruptTasks is enabled and configured such that escalation retires an entry by itself. Default 20. Not reloadable, not config-cascade aware. File: threadpool.properties.

SCR-1845

Summary: New Configuration Option for Expanding Nested LDAP Distribution Lists

Effective: 8.53.217 and later

In order to serve directories that model a distribution list as a member of another distribution list, the new option nestedDistributionListDepth is introduced for the contacts providers defined in contacts-provider-ldap.yml. It controls how many levels of such references are followed and resolved down to their leaf members. The option defaults to 0, which preserves the previous behavior of taking over a referenced list as a single member, and is evaluated per contacts provider section, taking effect after a configuration reload.

When expanding, an entry that is reachable through more than one of the nested lists is taken over once only, and the members of an expanded list are matched against the provider's folder filters just like any other member. A list that is referenced by one of its own members forms a cycle; such a reference is not followed a second time and is reported as a warning instead, so that a mistake in the directory does not keep the address book from being read.

No operator action is required by default. See the feature documentation for further details.

SCR-1843

Summary: New configuration options for capping how long IMAP responses are read from the primary and secondary account

Effective: 8.53.217 and later

A slow IMAP server can keep a request thread reading responses for minutes. The lean property com.openexchange.imap.readResponsesTimeout caps that, but has so far only been applied to external mail accounts. It can now be applied to the primary and to secondary accounts as well, through their own options - which, unlike the general one, carry no default and therefore never impose a cap unless an operator asks for it.

  • com.openexchange.imap.primary.readResponsesTimeout The maximum time in milliseconds spent reading the responses of a single IMAP command on the primary account. When it elapses, the command is aborted and reported to the client as a connection error. A value less than or equal to 0 is ignored, as is a non-numeric one. No default: while the option is absent no read responses timeout is applied at all. Reloadable, config-cascade aware. File: imap.properties.

  • com.openexchange.imap.secondary.readResponsesTimeout The same for secondary accounts. A value less than or equal to 0 is ignored, as is a non-numeric one. No default: while the option is absent no read responses timeout is applied at all. Reloadable, config-cascade aware. File: imap.properties.

External accounts are unaffected and keep evaluating com.openexchange.imap.readResponsesTimeout with its default of 60000.

SCR-1841

Summary: New configuration option for the AJAX job queue

Effective: 8.53.217 and later

The AJAX job queue now runs its jobs on a virtual-thread executor of its own instead of drawing from the shared virtual-thread budget.

  • com.openexchange.threadpool.jobqueue.maxConcurrency Limits how many AJAX job-queue jobs execute concurrently on the job-queue executor's virtual threads (OXJobQueue-*). A job holds its slot for its entire run and fans out onto the shared virtual-thread executor itself, so it draws from a budget separate from com.openexchange.threadpool.virtual.maxConcurrency. Size it by the number of long-running requests a node should process at once, not by heap. This is the first bound the job queue has had; previously a job occupied a platform worker for its entire run. A value of 0 (zero) disables the job-queue executor and runs jobs on the platform thread pool as before; no appsuite.executor.jobqueue.* meters are registered then. A value less than 0 (zero) is treated as 0 and logged. Default 256. Not reloadable, not config-cascade aware. File: threadpool.properties.

SCR-1839

Summary: New configuration option for remote invalidation of the in-memory cache layer

Effective: 8.53.217 and later

New configuration option for the cache.v2 in-memory caching layer in front of Redis: an in-memory cache - enabled by configuration or dynamically under load - now propagates invalidations to the other nodes' in-memory caches. Regions that fire cache events are mirrored through those events anyway; for all other regions a dedicated, listener-free pub/sub channel carries the invalidated keys (or the pattern of a mass invalidation), so the receiving nodes drop their replicas right away instead of serving them until the time-to-live elapses.

  • com.openexchange.cache.v2.redis.inmemory.remoteInvalidation Whether an in-memory cache propagates invalidations to the other nodes' in-memory caches. Effective with com.openexchange.cache.v2.redis.inmemory.enabled=true or with dynamic enabling configured through com.openexchange.cache.v2.redis.inMemoryCacheEnableThreshold. Disable it to trade consistency for less pub/sub traffic. Default true. Not reloadable, not config-cascade aware. File: redis.properties.

SCR-1836

Summary: New configuration option for the timer executor's concurrency

Effective: 8.53.217 and later

Timer tasks scheduled through the TimerService now run on a dedicated virtual-thread executor instead of the platform thread pool; the following option bounds that executor.

  • com.openexchange.threadpool.timer.maxConcurrency The maximum number of timer tasks executing concurrently on the timer executor's virtual threads (OXTimer-*). Once the limit is reached, due timer tasks spill over to the platform thread pool (OXWorker-*) until permits are free again; a spill-over is logged at WARN level at most once per minute. Raise the value when the meter appsuite.executor.timer.active sits at appsuite.executor.timer.concurrency.limit while appsuite.executor.timer.rejected increases. A value of 0 (zero) disables the timer executor entirely and runs all timer tasks on the platform thread pool as in previous versions; a negative value is treated as 0 and logged. Default 64. Not reloadable, not config-cascade aware. File: threadpool.properties.

SCR-1830

Summary: Renamed configuration properties keep resolving under their previous names

Effective: 8.53.217 and later

A number of configuration properties were renamed to consistent, fully-qualified names, for example com.openexchange.hazelcast.network.join to com.openexchange.hazelcast.network.join.mode and the bare legacy key JMXServerPort to com.openexchange.jmx.serverPort. Deployments that still configure an old name are not affected: when a renamed property is not set under its new name, the server automatically falls back to the value configured under the previous name. If both names are set, the new name wins. The fallback is a transitional measure and will be removed in a future release, so configurations should be migrated to the new names; every value served through the fallback is reported in the server log, typically at startup, as Deprecated key <previous name> detected. See the property changes documentation for the complete list of renamed properties with previous name, new name and, where a bare previous name only applies within one file, that file.

SCR-1829

Summary: Migrated middleware configuration to typed properties with built-in defaults and removed 55 shipped .properties files

Effective: 8.53.217 and later

The middleware configuration is migrated to typed property definitions whose default values live inside the server. As a consequence, 55 .properties files that only carried default values are no longer shipped to /opt/open-xchange/etc. The built-in defaults are identical to the values those files used to ship, so effective configuration is unchanged and no operator action is required. Overriding a default works as before: set the property in any .properties file in the configuration directory (the server reads them all, file names do not matter) or through the config cascade. Files that are read by name (configdb.properties, system.properties, whitelist.properties, the OAuth provider files, AdminUser.properties, Group.properties, Resource.properties, permissions.properties, caldav.properties and others) are still shipped. See the property documentation for the authoritative defaults. The removed files are listed in the property changes documentation.

SCR-1828

Summary: New configuration option for IMAP IDLE push

Effective: 8.53.217 and later

In order to decouple the number of users watched via IMAP IDLE from the size of the shared thread pool, IMAP IDLE cycles are now executed on virtual threads.

  • com.openexchange.push.imapidle.virtualThreads Controls whether IMAP IDLE cycles are executed on virtual threads instead of the shared timer thread pool. An IDLE cycle blocks until the IMAP server reports a change or the listener is aborted; on platform threads every idling user therefore occupies one thread of the pool that also serves HTTP requests. Set it to false to restore the previous behavior. The value is evaluated when a listener is started, so it takes effect for listeners started afterwards. Default true. Reloadable, not config-cascade aware. File: push_imapidle.properties.

Two meters are added to size the mechanism: appsuite.push.imapidle.listeners reports the IMAP IDLE push listeners registered on the node, and appsuite.push.imapidle.idling reports those currently waiting in an IMAP IDLE command, each holding an IMAP connection.

SCR-1827

Summary: New configuration options for the Redis connector start-up behavior

Effective: 8.53.217 and later

Two configuration options control how the Redis connector behaves while its bundle starts.

  • com.openexchange.redis.awaitEndPointOnStartup Whether bundle start-up awaits reachability of the Redis end-point. With the default the connector blocks until the end-point answers. Setting it to false moves the wait off the start-up path: the end-point is awaited in the background, with a growing but capped interval between attempts, so a pod starts and can be terminated cleanly even while Redis is unavailable. In either mode the RedisConnectorService is registered only once the end-point answered, so consumer bundles never start against an unreachable Redis; until then the node is up but not serviceable - a login attempt in that window fails. A condition that cannot resolve without a configuration change - rejected credentials above all - ends the background wait; the node then has no Redis functionality until it is restarted with a corrected configuration. This property applies to the regular Redis instance only; dedicated cache instances and remote sites always start without awaiting their end-point. Default true. Not reloadable, not config-cascade aware. File: redis.properties.

  • com.openexchange.redis.awaitEndPointBudgetMillis How long start-up awaits the Redis end-point before giving up, in milliseconds. Only relevant while com.openexchange.redis.awaitEndPointOnStartup is true. The default waits indefinitely, which is what a Redis that is merely slow to become available needs: loading a large dataset after a restart can take considerably longer than a few minutes, and every node of the installation is waiting for the same end-point. Set a value only where a bounded start-up is preferred over waiting it out; start-up then fails with an error instead of continuing to retry. A condition that cannot resolve without a configuration change - rejected credentials above all - is reported immediately regardless of this setting. A value less than or equal to 0 (zero) means no limit. Default 0. Not reloadable, not config-cascade aware. File: redis.properties.

SCR-1825

Summary: New configuration option for Redis Sentinel authentication

Effective: 8.53.217 and later

In order to connect to a password-protected Redis Sentinel, a new configuration option has been added.

  • com.openexchange.redis.sentinel.password Specifies the password used to authenticate against the Redis Sentinel nodes. Only effective if com.openexchange.redis.mode is set to sentinel. Sentinel authentication is separate from the credentials for the Redis nodes themselves, which remain configured through com.openexchange.redis.username and com.openexchange.redis.password. An empty value means the Sentinel nodes require no authentication. Set it only if the Sentinel nodes actually require authentication; otherwise they reject the AUTH command and the topology look-up fails. For a special Redis instance the option is available as com.openexchange.redis.[instanceId].sentinel.password, with [instanceId] being cache or the identifier of a remote site. Default empty. Not reloadable, not config-cascade aware. File: redis.properties.

SCR-1824

Summary: New property com.openexchange.mail.import.enforceFromValidation

Effective: 8.53.217 and later

The new lean configuration property com.openexchange.mail.import.enforceFromValidation controls whether the From of a message imported or appended into a folder through mail?action=import or mail?action=new is validated against the user's own addresses even when the request carries force=true. It defaults to false, is reloadable and config-cascade aware.

By default a force=true request skips that check, matching the established behavior the regular client relies on to import arbitrary messages such as migrated or forwarded .eml files. Setting it to true makes the check unconditional, so a message whose From the user does not own is rejected on import too, closing the path where such a message could later be re-sent under a foreign identity, e.g. through a redirect filter rule. The trade-off is that messages with a foreign sender can then no longer be imported.

No operator action is required by default. See the configuration documentation for further details.

SCR-1819

Summary: New properties for eml token lifetime, message size limit and concurrent token downloads

Effective: 8.53.217 and later

In order to bound what a token download may consume, three lean configuration properties are introduced. All of them are reloadable and config-cascade aware.

  • com.openexchange.mail.emlToken.ttl sets how long a token issued through mail?action=emlToken stays valid, defaulting to 300000 milliseconds. The lifetime is fixed: it starts when the token is issued and is not extended by accessing it. Only the start of the download has to fall into that window.
  • com.openexchange.mail.emlToken.maxMessageSize refuses to issue such a token for messages larger than 1073741824 bytes. It is evaluated when the token is issued; messages whose size the mail back-end does not report pass unchecked. A value less than or equal to 0 disables the check.
  • com.openexchange.mail.attachmentToken.maxConcurrentDownloads bounds how many token downloads one user may have in flight at the same time on one node, defaulting to 20. It covers downloads of single attachments as well as of whole messages through /ajax/mail.attachment; requests beyond the limit are answered with status 429. A value less than or equal to 0 disables the limit.

Keep the last value below the number of connections the mail back-end grants a single user, so that an excess of downloads is rejected with 429 rather than running into a connection error. The counter is kept per node, hence the effective limit across a cluster is the value times the number of nodes.

That property applies to the pre-existing attachment download path as well, so a user with more downloads in flight than the limit allows now receives 429 where previously every request was served. It complements com.openexchange.servlet.maxRate, which limits requests over time rather than at a time. No operator action is required by default.

SCR-1817

Summary: New configuration options for the Caffeine cache helper and ICAP OPTIONS caching

Effective: 8.53.217 and later

New configuration options introduced together with the replacement of the remaining Guava caches by Caffeine and the shared cache-loading helper this introduced.

  • com.openexchange.caching.caffeine.loadTimeoutSeconds The number of seconds a thread awaits a cache value that another thread is currently loading, before it gives up and the request fails with an error. The load itself stays in flight, so the remaining waiters and any later caller keep sharing it rather than starting a second load against a back end that is already slow. Applies only to caches that load through the shared Caffeine helper. A value less than or equal to 0 (zero) is ignored and the default is used. Default 10. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.caching.caffeine.maxLoadSeconds The number of seconds after which a cache load that is still in flight counts as stuck rather than merely slow. The next caller running into com.openexchange.caching.caffeine.loadTimeoutSeconds then drops that load and fails the threads waiting on it, so a loader that never returns cannot render its cache key unusable for the lifetime of the process. Must be set comfortably above the slowest legitimate load; a call site that declares a longer wait of its own raises the ceiling accordingly. A value less than or equal to 0 (zero) is ignored and the default is used. Default 60. Reloadable, not config-cascade aware. No dedicated properties file.

  • com.openexchange.icap.client.optionsTtlSeconds The life time in seconds of a cached ICAP OPTIONS response that carries no Options-TTL header. Responses that do carry that header expire after the time the ICAP server advertises; this option governs only the case where the server omits it. A value less than or equal to 0 (zero) disables caching for those responses, which makes every scan perform an OPTIONS round trip on the calling thread first. Default 300. Reloadable, not config-cascade aware. No dedicated properties file.

SCR-1806

Summary: New properties for the JWKS retrieval timeouts

Effective: 8.53.217 and later

Retrieval of the JWK set used to validate OAuth 2.0 access tokens, from the end-point configured through com.openexchange.oauth.provider.jwt.jwksUri, is now bounded by two new lean configuration properties instead of by the fixed defaults of the underlying library:

com.openexchange.oauth.provider.jwt.jwksConnectTimeout = 2000
com.openexchange.oauth.provider.jwt.jwksReadTimeout = 3000

Both are given in milliseconds and apply to a single retrieval attempt. They are reloadable and config-cascade aware. The previous effective values were 500 ms each, which was too tight for a JWKS end-point reached over a network.

A retrieval is attempted twice, so the sum of both values should stay well below 15000 ms, the time a request waits for a retrieval that another request has already started. A configured pair that does not satisfy this, or that is not positive, is ignored in favour of the defaults above and reported in the log.

Retrieval also became resilient without any configuration change: a failed retrieval is retried, the retrieved set is cached and refreshed ahead of its expiry, and while the end-point is unreachable the last retrieved set continues to be used rather than rejecting otherwise valid access tokens.

Related behavioural change, for completeness: when the signing keys cannot be obtained at all, an OAuth-authenticated HTTP API request is now answered with HTTP 503 and error: temporarily\_unavailable instead of HTTP 401 and error: invalid\_token. Access tokens that genuinely fail validation are still answered with HTTP 401 as before.

See the property documentation https://documentation.open-xchange.com/components/middleware/config/8/#mode=search&term=jwksConnectTimeout for further details.

Packaging/Bundles

SCR-1831

Summary: Consolidated configuration bundles into com.openexchange.config.common

Effective: 8.53.217 and later

The shared configuration types are reorganized into dedicated bundles. Newly introduced:

  • com.openexchange.config.common - contains the classic ConfigurationService, the reload types and the lean configuration API; the com.openexchange.config package moves here from com.openexchange.configread, which remains as the provider implementation.
  • com.openexchange.config.universal - the relocated user-configuration API.
  • com.openexchange.config.mapping - resolves renamed property keys to their previous names.
  • com.openexchange.admin.common, com.openexchange.sessiond.config and com.openexchange.timer - split out of their host bundles to break dependency cycles.

The bundle com.openexchange.config.lean is renamed to com.openexchange.config.lean.impl; the API package name com.openexchange.config.lean is unchanged. All affected packages are shipped as before; install lists that pin individual bundles must be updated accordingly.

8.52.190

3rd Party Libraries/License Change

SCR-1796

Summary: Updated Netty libraries from v4.2.15 to v4.2.16 in bundle io.netty

Effective: 8.52.190 and later

Updated Netty libraries from v4.2.15.Final to v4.2.16.Final (patch version update) in bundle io.netty. Drop-in replacement of all 22 netty-* artifacts (binary and source JARs). No artifacts were added or removed and there are no exported-package changes relative to 4.2.15.

Updated artifacts (4.2.15.Final → 4.2.16.Final):

  • netty-buffer-4.2.16.Final.jar
  • netty-codec-base-4.2.16.Final.jar
  • netty-codec-compression-4.2.16.Final.jar
  • netty-codec-dns-4.2.16.Final.jar
  • netty-codec-http-4.2.16.Final.jar
  • netty-codec-http2-4.2.16.Final.jar
  • netty-codec-marshalling-4.2.16.Final.jar
  • netty-codec-protobuf-4.2.16.Final.jar
  • netty-codec-socks-4.2.16.Final.jar
  • netty-codec-xml-4.2.16.Final.jar
  • netty-common-4.2.16.Final.jar
  • netty-handler-4.2.16.Final.jar
  • netty-handler-proxy-4.2.16.Final.jar
  • netty-resolver-4.2.16.Final.jar
  • netty-resolver-dns-4.2.16.Final.jar
  • netty-transport-4.2.16.Final.jar
  • netty-transport-native-unix-common-4.2.16.Final.jar
  • netty-transport-classes-epoll-4.2.16.Final.jar
  • netty-transport-native-epoll-4.2.16.Final.jar
  • netty-transport-classes-io_uring-4.2.16.Final.jar
  • netty-transport-classes-kqueue-4.2.16.Final.jar
  • netty-transport-native-kqueue-4.2.16.Final.jar

Unchanged: netty-tcnative-classes-2.0.80.Final.jar (already current). No configuration or behavior changes within the 4.2.x line. Consumers use OSGi Import-Package version ranges, so no dependent-bundle adjustments are needed. Lettuce (bundle io.lettuce) is unaffected and remains at v7.6.0.RELEASE (already the latest release).

SCR-1795

Summary: Jakarta EE 11: upgrade target platform to Jersey 4.0.2 / jakarta.ws.rs 4.0 / HK2 4.0.1

Effective: 8.52.190 and later

Upgrades the shared target platform (com.openexchange.bundles) to the Jakarta EE 11 RESTful services stack.

  • Jersey 3.1.3 -> 4.0.2 (container-servlet-core merged upstream; unused apache-connector dropped)
  • jakarta.ws.rs-api 3.1.0 -> 4.0.0; jakarta.annotation-api 2.1.1 -> 3.0.0; jakarta.validation-api 3.0.2 -> 3.1.0
  • HK2 3.0.5 -> 4.0.1 (GA); aopalliance-repackaged -> 4.0.1; osgi-resource-locator 1.0.3 -> 3.0.0
  • jackson-jakarta-rs providers (2.22.0): ws.rs import range widened in place to [3.0.0,5.0.0) so they resolve against ws.rs 4.0 (no released version supports ws.rs 4.0 yet; the MessageBodyReader/Writer contract is unchanged)
  • MicroProfile Health kept at 3.0: version 4.0.1 imports jakarta.enterprise.util [3.0,4.0), incompatible with the EE 11 CDI package version 4.0, so it cannot resolve against an EE 11 CDI stack. Legacy javax cdi-api 2.0.SP1 and javax.inject provider retained.

Package import ranges for jakarta.ws.rs and org.glassfish.jersey widened [3.1,4) -> [4,5) in the affected core bundles. No configuration, HTTP API or behavior change. Dependent repositories pinning jakarta.ws.rs [3.1,4) (custom, comcast, cloud-plugins, exchange-interop, plugins, usm, kpn) must widen their ranges in lockstep.

SCR-1794

Summary: Upgrade Box SDK to generated Box Java SDK 10.15.1 (com.box.sdkgen)

Effective: 8.52.190 and later

The Box.com file storage bundle com.openexchange.file.storage.boxcom is migrated from the retired classic Box Java SDK (com.box:box-java-sdk 4.16.4, package com.box.sdk) to the current generated Box Java SDK (com.box:box-java-sdk 10.15.1, package com.box.sdkgen). The generated SDK replaces the object-graph API of BoxFolder/BoxFile handles with a manager and DTO API - a BoxClient exposing FoldersManager, FilesManager, UploadsManager, DownloadsManager, SearchManager and UsersManager that return schema DTOs - so the whole resource access layer of the bundle is rewritten. The classic BoxAPIConnection is replaced by a BoxClient backed by a small App-Suite-owned Authentication implementation whose access token is refreshed externally by App Suite's OAuth service, leaving the token life-cycle unchanged, and com.box.sdk.BoxAPIException is replaced by com.box.sdkgen.box.errors.BoxAPIError / BoxSDKError. The embedded third-party libraries change accordingly: box-java-sdk 10.15.1 and jose4j 0.9.6 are embedded, minimal-json and zstd-jni are dropped, and jackson, okhttp/okio, bouncycastle and slf4j are consumed from the platform bundles. There is no configuration, HTTP API or externally visible behavior change; the migration is internal to the bundle and no dependent bundle consumes the Box SDK packages. Since there is no Box OAuth setup in the development environment, the bundle was verified to compile and to link and run against the live Box API via a standalone smoke test on JDK 25; full end-to-end verification against a real Box account is pending as a QA step before release.

SCR-1792

Summary: Upgrade Cassandra driver to Apache Cassandra java-driver 4.19.3

Effective: 8.52.190 and later

The Cassandra driver embedded in com.openexchange.nosql.cassandra is upgraded from the end-of-life DataStax cassandra-driver 3.11.5 to Apache Cassandra java-driver 4.19.3. The bundle keeps exposing the driver API to depending packages, but the exported packages move from com.datastax.driver.* to com.datastax.oss.driver.api.*. All properties keep their keys; their semantics follow the 4.x driver model of fixed-size connection pools and unified load balancing. New is com.openexchange.nosql.cassandra.localDatacenter (default empty), the datacenter considered local by the load balancing policy - if empty it is inferred from the contact points, which is only reliable for single-datacenter clusters, so multi-datacenter deployments should set it explicitly. Removed without a 4.x equivalent are minimumLocalConnectionsPerNode and minimumRemoteConnectionsPerNode (pools now have a fixed size configured via the existing maximum properties), idleConnectionTrashTimeout (connections are no longer trashed), acquisitionQueueMaxSize (the queue no longer exists) and maximumRequestsPerRemoteConnection (maximumRequestsPerLocalConnection now applies to all connections). Changed semantics: loadBalancingPolicy still accepts the legacy values RoundRobin, DCAwareRoundRobin and DCTokenAwareRoundRobin but all map to the token-aware datacenter-local round-robin the driver ships, with the default changed to DCTokenAwareRoundRobin; poolingHeartbeat can no longer be disabled with 0, which falls back to the driver default of 30 seconds; readTimeout now maps to the driver's overall request timeout rather than the per-read socket timeout; and enableQueryLogger now logs slow and failed statements instead of all statements. The JMX MBeans below com.openexchange.nosql.cassandra are kept - attributes without a 4.x equivalent were removed and aborted-request counters were added.

SCR-1787

Summary: Introduced Apache HttpClient 5 platform bundles and HttpClient-5-based managed HTTP client service

Effective: 8.52.190 and later

First step of the HttpClient 4.x (EOL) to 5.x migration (core#544):

  • Added httpclient5 5.6.2, httpcore5 5.4.3 and httpcore5-h2 5.4.3 as target platform bundles (com.openexchange.bundles). The upstream jars ship without OSGi metadata, so OSGi manifests are re-added (versioned exports; optional imports for conscrypt/brotli4j/zstd/commons-compress). Provided additively next to the existing 4.x bundles.
  • Added an HttpClient-5-based twin of the managed HTTP client machinery as com.openexchange.rest.client.httpclient.v5 (service, managed client with hard connect/read timeout watchers, pooling connection manager with monitoring metrics, cookie stores and lenient cookie spec, security route planners and redirect strategies, configuration SPI). The twin service is registered in parallel to the 4.x service so that consuming bundles can migrate individually.
  • Migrated com.openexchange.conference.webhook as the first consumer (blueprint).

The 4.x based service and platform bundles remain untouched until all consumers (incl. dependent repositories) are migrated.

SCR-1786

Summary: Upgraded Apache PDFBox from 2.0.x to 3.0.7

Effective: 8.52.190 and later

Upgraded the PDF stack used for mail export (com.openexchange.mail.exportpdf.impl) and the target platform:

  • pdfbox/fontbox/xmpbox upgraded from 2.0.27 to 3.0.7 (new companion artifact pdfbox-io)
  • Unused pdfbox-tools and preflight embeds removed (never referenced by code)
  • pdfbox2-layout 1.0.1 has no PDFBox 3 compatible release; its MIT-licensed sources are vendored into the bundle (rst.pdfbox.layout.*) and ported to the PDFBox 3 API

  • Target platform pdfbox/fontbox 2.0.30 upgraded to 3.0.7 (+ pdfbox-io); consumed by openexchange-test (ExportPDFTest)

  • Code migrated to the PDFBox 3 API: Loader.loadPDF instead of PDDocument.load, Standard14Fonts.FontName based font construction, MemoryUsageSetting.streamCache, PDPageContentStream.AppendMode, xmpbox createAndAddPDFAIdentificationSchema

SCR-1785

Summary: Upgraded OpenSAML from 3.4.5 to 5.2.3

Effective: 8.52.190 and later

Upgraded the SAML stack in com.openexchange.saml from the EOL OpenSAML 3.4.5 to the supported OpenSAML 5.2.3:

  • All opensaml-* artifacts upgraded from 3.4.5 to 5.2.3 (opensaml-core is split into opensaml-core-api/opensaml-core-impl upstream)
  • net.shibboleth.utilities:java-support 7.5.1 replaced by the modular net.shibboleth shared libraries 9.2.3 (shib-support/shib-security/shib-networking/shib-velocity); exported packages move from net.shibboleth.utilities.java.support.* to net.shibboleth.shared.*

  • xmlsec upgraded from 2.3.4 to 3.0.6, metrics-core from 3.1.2 to 4.2.39

  • New embedded transitives httpclient5 5.3.1/httpcore5 5.2.5 (required by the OpenSAML 5 initialization service)

  • Obsolete joda-time usage migrated to java.time.Instant; obsolete Apache Xerces Import-Package entries removed (OpenSAML 5 configures JDK XML parser limits that Xerces does not understand)

  • OpenSAML >= 4.1 is not published to Maven Central; the Shibboleth releases repository is added to the build with content filtering for org.opensaml/net.shibboleth

SCR-1784

Summary: Upgraded Google API/HTTP/OAuth client stack and Firebase Admin SDK

Effective: 8.52.190 and later

Upgraded the Google client stack (com.google.api.client) and Firebase Admin SDK (com.google.firebase):

  • google-http-client (+ apache-v2/appengine/gson/jackson2/protobuf/xml modules) upgraded from 1.43.3/1.42.3 to 2.1.1
  • google-api-client (+ appengine/gson/jackson2/protobuf/servlet/xml modules) upgraded from 2.2.0 to 2.9.0
  • google-oauth-client (+ appengine/java6 modules) upgraded from 1.34.1 to 1.39.0
  • google-api-services calendar/drive/gmail/people upgraded to current revisions (rev20260614/rev20260624/rev20260525/rev20251117); oauth2 unchanged upstream
  • api-common upgraded from 2.15.0 to 2.65.0
  • grpc-context upgraded from 1.27.2 to 1.70.0 (new companion grpc-api 1.70.0)
  • New embedded transitive: google-auth-library-credentials/google-auth-library-oauth2-http 1.47.0
  • firebase-admin upgraded from 9.2.0 to 9.10.0; its default HTTP transport (ApacheHttp2Transport) requires embedding httpclient5 5.3.1, httpcore5 5.2.4 and httpcore5-h2 5.2.4; nimbus-jose-jwt is consumed from the platform bundle (com.nimbus)

Merged to main via core!5065 (commit c2415d6f1dd).

SCR-1780

Summary: Upgraded Apache CXF to 4.2.2 and Metro JAX-WS runtime to 4.0.5

Effective: 8.52.190 and later

Upgraded the SOAP stack embedded in the com.openexchange.soap.common bundle:

  • 11 cxf-* libraries upgraded from 4.0.7 to 4.2.2

  • jakarta.xml.ws-api-3.0.1.jar upgraded to jakarta.xml.ws-api-4.0.3.jar

  • jaxws-rt-3.0.2.jar (Metro) upgraded to jaxws-rt-4.0.5.jar

  • saaj-impl-2.0.1.jar upgraded to saaj-impl-3.0.6.jar

  • neethi-3.2.1.jar upgraded to neethi-3.2.2.jar, xmlschema-core-2.3.1.jar to xmlschema-core-2.3.2.jar, gmbal-api-only-4.0.3.jar to gmbal-api-only-4.1.2.jar, mimepull-1.9.15.jar to mimepull-1.11.0.jar, streambuffer-2.0.2.jar to streambuffer-2.1.0.jar

The legacy javax.xml.ws compatibility libraries stay unchanged.

SCR-1775

Summary: Upgraded Spring Framework to 7.0.8 and jOOX to 2.0.1

Effective: 8.52.190 and later

Upgraded third-party libraries embedded in the com.openexchange.xml bundle:

  • spring-core-6.2.15.jar upgraded to spring-core-7.0.8.jar
  • spring-beans-6.2.15.jar upgraded to spring-beans-7.0.8.jar
  • spring-jcl-6.2.15.jar removed (merged into spring-core in Spring Framework 7)
  • joox-1.5.0.jar upgraded to joox-2.0.1.jar

SCR-1774

Summary: Upgraded Hazelcast library to 5.7.0

Effective: 8.52.190 and later

Upgraded third-party library embedded in the com.hazelcast bundle:

  • hazelcast-5.3.8.jar upgraded to hazelcast-5.7.0.jar

Note for operators: Hazelcast Open Source does not support rolling upgrades across minor versions. During a deployment upgrade, middleware nodes running 5.7.0 will form a separate cluster from remaining 5.3.8 nodes until the rollout completes; cluster-wide volatile data (e.g. sessions held in Hazelcast maps) follows the usual full-cluster-upgrade semantics.

SCR-1773

Summary: Upgraded OWASP ESAPI library to 2.7.0.0

Effective: 8.52.190 and later

Upgraded third-party library embedded in the com.openexchange.common bundle:

  • esapi-2.0.1.jar upgraded to esapi-2.7.0.0.jar

Only the org.owasp.esapi.codecs package is consumed by the middleware (HTML entity decoding in com.openexchange.html); the new transitive dependency tree of the unused ESAPI reference implementation (antisamy, batik, httpclient) is excluded from the bundle.

SCR-1772

Summary: Upgraded Box Java SDK to 4.16.4

Effective: 8.52.190 and later

Upgraded third-party libraries embedded in the com.openexchange.file.storage.boxcom bundle:

  • box-java-sdk-2.54.0.jar upgraded to box-java-sdk-4.16.4.jar (latest release of the classic com.box.sdk API line; the 10.x line is a different, generated SDK with a new API)
  • jose4j-0.5.5.jar upgraded to jose4j-0.9.4.jar
  • zstd-jni-1.5.7-2.jar newly embedded (response decompression support of the SDK)

The SDK now performs HTTP via OkHttp, which is consumed from the com.squareup.okhttp3 platform bundle; that bundle additionally exports the kotlin base package. File thumbnails are retrieved through the file representations endpoint, as the SDK removed the legacy thumbnail API.

SCR-1771

Summary: Upgraded Dropbox Core SDK to 8.0.1

Effective: 8.52.190 and later

Upgraded third-party library embedded in the com.openexchange.oauth.dropbox bundle:

  • dropbox-core-sdk-3.1.5.jar upgraded to dropbox-core-sdk-8.0.1.jar

SCR-1770

Summary: Upgraded Apache XML-RPC libraries to 6.1.0

Effective: 8.52.190 and later

Upgraded third-party libraries embedded in middleware bundles:

  • com.openexchange.parallels: xmlrpc-client-5.0.0.jar, xmlrpc-common-5.0.0.jar, xmlrpc-server-5.0.0.jar upgraded to 6.1.0; ws-commons-util-1.0.2.jar upgraded to ws-commons-util-1.1.0.jar
  • com.openexchange.eas.provisioning.action.sms: xmlrpc-client-5.0.0.jar, xmlrpc-common-5.0.0.jar upgraded to 6.1.0; ws-commons-util-1.0.2.jar upgraded to ws-commons-util-1.1.0.jar

SCR-1769

Summary: Upgraded lib-recur library to 0.17.1

Effective: 8.52.190 and later

Upgraded third-party library embedded in the com.openexchange.chronos.common bundle:

  • lib-recur-0.10.jar upgraded to lib-recur-0.17.1.jar
  • jems2-2.23.1.jar newly embedded (required by lib-recur 0.17)

The recurrence rule expansion engine (org.dmfs.rfc5545.recur) is updated to the latest upstream release. The legacy recurrence-set helper classes that upstream removed in favor of a redesigned API are retained as sources in the bundle, so the iteration behavior of the calendar recurrence service is unchanged (verified by the full recurrence test suite, 50000+ tests).

SCR-1768

Summary: Upgraded ez-vcard library to 0.12.2

Effective: 8.52.190 and later

Upgraded third-party library embedded in the com.openexchange.contact.vcard.impl bundle:

  • ez-vcard-0.10.6.jar upgraded to ez-vcard-0.12.2.jar

The vCard date mappings were adopted to the library's new java.time-based API. Date properties (BDAY, ANNIVERSARY) are now handled as LocalDate without the former local-timezone adjustment workarounds; the serialized vCard output is unchanged.

SCR-1767

Summary: Upgraded ROME, jaudiotagger, Caffeine, MaxMind GeoIP2 and libphonenumber libraries

Effective: 8.52.190 and later

Upgraded third-party libraries embedded in middleware bundles:

  • com.openexchange.rss: rome-1.19.0.jar upgraded to rome-2.1.0.jar, rome-utils-1.19.0.jar upgraded to rome-utils-2.1.0.jar (rome-fetcher stays at 1.19.0, no 2.x release exists)
  • com.openexchange.server: jaudiotagger-2.2.5.jar upgraded to jaudiotagger-3.0.1.jar
  • com.openexchange.oauth.provider.impl: caffeine-2.8.5.jar upgraded to caffeine-3.2.4.jar
  • com.openexchange.geolocation.maxmind.binary: geoip2-2.17.0.jar upgraded to geoip2-5.1.0.jar, maxmind-db-2.1.0.jar upgraded to maxmind-db-4.1.0.jar
  • com.openexchange.sms: libphonenumber-8.13.1.jar upgraded to libphonenumber-9.0.34.jar

SCR-1766

Summary: Upgraded webauthn-server-core, reactor-core and zero-allocation-hashing libraries

Effective: 8.52.190 and later

Upgraded third-party libraries embedded in middleware bundles:

  • com.openexchange.webauthn: webauthn-server-core-2.5.3.jar upgraded to webauthn-server-core-2.9.0.jar, yubico-util-2.5.3.jar upgraded to yubico-util-2.9.0.jar
  • io.lettuce: reactor-core-3.6.6.jar upgraded to reactor-core-3.8.6.jar
  • net.openhft.hashing: zero-allocation-hashing-0.16.jar upgraded to zero-allocation-hashing-2026.0.jar

SCR-1765

Summary: Upgraded BouncyCastle libraries to 1.84 in target platform

Effective: 8.52.190 and later

Upgraded BouncyCastle libraries in target platform (com.openexchange.bundles):

  • bcmail-jdk18on-1.79.jar upgraded to bcmail-jdk18on-1.84.jar
  • bcpg-jdk18on-1.79.jar upgraded to bcpg-jdk18on-1.84.jar
  • bcpkix-jdk18on-1.79.jar upgraded to bcpkix-jdk18on-1.84.jar
  • bcprov-jdk18on-1.79.jar upgraded to bcprov-jdk18on-1.84.jar
  • bcutil-jdk18on-1.79.jar upgraded to bcutil-jdk18on-1.84.jar

BouncyCastle 1.84 removed the legacy post-quantum algorithm packages org.bouncycastle.pqc.crypto.rainbow, org.bouncycastle.pqc.jcajce.provider.gmss and org.bouncycastle.pqc.jcajce.provider.mceliece; stale (unused) imports of these packages were removed from the com.openexchange.saml bundle manifest. The OpenPGP API change of PGPKeyEncryptionMethodGenerator.generate(...) was adopted in com.openexchange.pgp.core (wire format of generated PKESK packets is unchanged).

SCR-1763

Summary: Upgraded OkHttp to v5.4.0 in com.squareup.okhttp3

Effective: 8.52.190 and later

Upgrades OkHttp in the encapsulated bundle com.squareup.okhttp3 to the 5.x line, a deliberate major migration since the 4.x line ended with 4.12.0 in November 2023: okhttp 4.12.0 becomes okhttp-jvm 5.4.0 (the Kotlin-Multiplatform jvm artifact), okhttp-sse and logging-interceptor move to 5.4.0, okio-jvm to 3.17.0 and kotlin-stdlib to 2.1.21, while the obsolete okio umbrella jar and kotlin-stdlib-common/-jdk8 are removed. The stale Bundle-Version is corrected from 4.11.0 to 5.4.0 and Import-Package is reduced to the jdeps-verified set actually referenced. The only middleware consumer is com.openexchange.jmap, which compiles and passes its unit tests against 5.4.0; the openexchange-test harness was adapted as well, since okhttp3.JavaNetCookieJar moved to the package okhttp3.java.net.cookiejar in 5.x.

SCR-1762

Summary: Upgraded Liquibase to v5.0.3

Effective: 8.52.190 and later

Upgraded the embedded database migration engine in the encapsulated liquibase.core wrapper bundle:

  • liquibase-core-4.33.0.jar upgraded to liquibase-core-5.0.3.jar
  • opencsv-5.11.2.jar upgraded to opencsv-5.12.0.jar

Liquibase 5.0.x is a major release, but the exported package set and external dependency surface are identical to 4.33.0, so Export-Package/Import-Package stay structurally unchanged. The in-house Liquibase extensions in com.openexchange.database.migration (custom ChangeLogHistoryService, XML changelog parser, preconditions, SLF4J logging) compile and pass their tests against the 5.0.3 SPIs without source changes.

Checksum stability was verified end-to-end against MariaDB: a DATABASECHANGELOG populated with legacy checksums is recognized as already-applied and left untouched (no changeset re-execution), preserving rollback compatibility.

SCR-1755

Summary: Updated Kubernetes Java Client (fabric8) from v7.5.2 to v7.8.0

Effective: 8.52.190 and later

Updated fabric8 Kubernetes Java Client from v7.5.2 to v7.8.0 (minor version migration) in bundle io.fabric8.kubernetes:

  • kubernetes-client-7.8.0.jar
  • kubernetes-client-api-7.8.0.jar
  • kubernetes-httpclient-jdk-7.8.0.jar
  • kubernetes-model-admissionregistration-7.8.0.jar
  • kubernetes-model-apiextensions-7.8.0.jar
  • kubernetes-model-apps-7.8.0.jar
  • kubernetes-model-autoscaling-7.8.0.jar
  • kubernetes-model-batch-7.8.0.jar
  • kubernetes-model-certificates-7.8.0.jar
  • kubernetes-model-common-7.8.0.jar
  • kubernetes-model-coordination-7.8.0.jar
  • kubernetes-model-core-7.8.0.jar
  • kubernetes-model-discovery-7.8.0.jar
  • kubernetes-model-events-7.8.0.jar
  • kubernetes-model-extensions-7.8.0.jar
  • kubernetes-model-flowcontrol-7.8.0.jar
  • kubernetes-model-gatewayapi-7.8.0.jar
  • kubernetes-model-metrics-7.8.0.jar
  • kubernetes-model-networking-7.8.0.jar
  • kubernetes-model-node-7.8.0.jar
  • kubernetes-model-policy-7.8.0.jar
  • kubernetes-model-rbac-7.8.0.jar
  • kubernetes-model-resource-7.8.0.jar
  • kubernetes-model-scheduling-7.8.0.jar
  • kubernetes-model-storageclass-7.8.0.jar
  • zjsonpatch-7.8.0.jar
  • snakeyaml-engine-3.0.1.jar (upgraded from v2.10)

The generex-1.0.2.jar and automaton-1.11-8.jar libraries were dropped; they are no longer referenced by the Kubernetes client since v7.7.0.

Exported packages follow upstream model changes: io.fabric8.kubernetes.api.model.clusterapi.v1beta1 was replaced by io.fabric8.kubernetes.api.model.clusterapi.core.v1beta1, io.fabric8.kubernetes.api.model.storagemigration.v1alpha1 by io.fabric8.kubernetes.api.model.storagemigration.v1beta1; new exports io.fabric8.kubernetes.api.model.scheduling.v1alpha2 and io.fabric8.kubernetes.api.model.resource.v1.

The bundle now additionally imports org.apache.commons.compress.archivers, org.apache.commons.compress.archivers.tar and org.apache.commons.compress.utils (required by pod upload/copy code paths). Stale imports of okhttp3/okio and SnakeYAML 1.x packages were removed; no code path references them.

SCR-1754

Summary: Migrated S3 file storage to AWS SDK for Java v2

Effective: 8.52.190 and later

Migrates the S3 file storage (com.openexchange.filestore.s3) from the AWS SDK for Java v1, which reached end of support on 2025-12-31, to the AWS SDK for Java v2. The encapsulating bundle com.amazonaws is removed from the target platform and from the open-xchange-filestore-s3 packaging and replaced by the new bundle software.amazon.awssdk (SDK v2 2.46.20), embedding the s3, sts, kms, apache-client and netty-nio-client modules plus amazon-s3-encryption-client-java 3.6.1, reactive-streams 1.0.4 and saaj-impl 2.0.1; Netty packages are imported from the existing io.netty target platform bundle. The SDK v2 signs all requests with AWS signature version 4, so the configured S3 end-point must support SigV4 and the properties com.openexchange.filestore.s3client.[clientID].signerOverride and com.openexchange.filestore.s3.[filestoreID].signerOverride are deprecated and have no effect anymore. Objects written by the SDK v1 encryption client, including the legacy "EncryptionOnly" format, remain readable; newly written objects use authenticated AES-GCM content encryption with an RSA-OAEP key wrap and can no longer be read by previous App Suite versions, so there is no rollback for newly written encrypted objects. Implicit CRC checksums are disabled (WHEN_REQUIRED) so uploads keep sending plain Content-MD5. The Prometheus metrics keep their names and tags, but the request timer's type tag now carries SDK v2 operation names, the byte throughput counter is derived from Content-Length headers, and the SDK v1 per-request latency logging no longer exists.

SCR-1752

Summary: Upgraded Micrometer to 1.17.0 and migrated Prometheus registry to prometheus-metrics (client_java 1.x)

Effective: 8.52.190 and later

Upgrades the encapsulated Micrometer libraries in the com.openexchange.metrics.micrometer PDE bundle to 1.17.0 and migrates the Prometheus registry from the end-of-life Prometheus Java simpleclient to prometheus-metrics (client_java 1.7.0); HdrHistogram moves to 2.2.2 and LatencyUtils is dropped. The Micrometer Prometheus registry moved from package io.micrometer.prometheus to io.micrometer.prometheusmetrics and the bundle export changed accordingly, so any OSGi bundle importing the old package must switch (in this repository only com.openexchange.redis was affected). The /metrics scrape servlet is now io.prometheus.metrics.exporter.servlet.jakarta.PrometheusMetricsServlet; bind point and BasicAuth handling are unchanged. The 1.x text exposition differs in details: label sets no longer carry a trailing comma, sample values are rendered canonically, and all data points of a metric family must share the same type. Because of the last constraint, tag-scoped histogram and SLO filters now force the classic histogram type for the whole metric family and expose a single sentinel bucket for tag combinations with the histogram disabled - without this guard the whole scrape would fail with HTTP 500. Name-scoped filters behave as before.

SCR-1750

Summary: Updated Netty libraries from v4.1.132 to v4.2.15 and Lettuce from v6.8.2 to v7.6.0

Effective: 8.52.190 and later

Updated Netty libraries from v4.1.132 to v4.2.15 (minor version migration) in bundle io.netty:

  • netty-buffer-4.2.15.Final.jar
  • netty-codec-base-4.2.15.Final.jar (new; codec split in Netty 4.2)
  • netty-codec-compression-4.2.15.Final.jar (new)
  • netty-codec-dns-4.2.15.Final.jar
  • netty-codec-http2-4.2.15.Final.jar
  • netty-codec-http-4.2.15.Final.jar
  • netty-codec-marshalling-4.2.15.Final.jar (new)
  • netty-codec-protobuf-4.2.15.Final.jar (new)
  • netty-codec-socks-4.2.15.Final.jar
  • netty-codec-xml-4.2.15.Final.jar (new)
  • netty-common-4.2.15.Final.jar
  • netty-handler-4.2.15.Final.jar
  • netty-handler-proxy-4.2.15.Final.jar
  • netty-resolver-4.2.15.Final.jar
  • netty-resolver-dns-4.2.15.Final.jar
  • netty-transport-4.2.15.Final.jar
  • netty-transport-native-unix-common-4.2.15.Final.jar
  • netty-transport-classes-epoll-4.2.15.Final.jar
  • netty-transport-native-epoll-4.2.15.Final.jar
  • netty-transport-classes-io_uring-4.2.15.Final.jar (new native transport classes)
  • netty-transport-classes-kqueue-4.2.15.Final.jar
  • netty-transport-native-kqueue-4.2.15.Final.jar
  • netty-tcnative-classes-2.0.80.Final.jar

The netty-codec jar was dropped (empty aggregator in 4.2). Exported package io.netty.handler.ssl.ocsp no longer exists in Netty 4.2; new exports: io.netty.channel.uring plus shaded jctools sub-packages.

Note: Netty 4.2 changes the default ByteBuf allocator from pooled to adaptive. The previous behavior can be restored via system property -Dio.netty.allocator.type=pooled.

Updated Lettuce Redis client from v6.8.2 to v7.6.0 (major version upgrade, requires Netty 4.2) in bundle io.lettuce:

  • lettuce-core-7.6.0.RELEASE.jar
  • redis-authx-core-0.1.1-beta2.jar (new mandatory dependency, MIT license)

Bundle now additionally imports org.slf4j (hard dependency of Lettuce 7.x). Embedded reactor-core-3.6.6.jar and reactive-streams-1.0.4.jar remain unchanged.

SCR-1749

Summary: Upgraded Grizzly to 5.0.2

Effective: 8.52.190 and later

Upgrades the encapsulated Grizzly libraries in the com.openexchange.http.grizzly PDE bundle from 5.0.1 to 5.0.2 (grizzly-http-all plus the three monitoring artifacts), with the transitive shifts gmbal 4.1.2 and pfl 5.1.1. Grizzly 5.0.2 replaces the HttpResponsePacket acknowledgement API with an interim-response model, so CustomHttpCodecFilter now sets the interim status and lets the codec serialize the status line instead of hand-building the bytes; the wire format of HTTP/1.1 100 Continue is unchanged. Grizzly 5.0.2 also enables strict RFC 9110 validation of HTTP header names and values by default, so requests carrying malformed headers are now rejected with 400 Bad Request during parsing, hardening against request smuggling. The switches are exposed as the lean properties com.openexchange.http.grizzly.strictHeaderNameValidation and com.openexchange.http.grizzly.strictHeaderValueValidation (both default true, read on server start); setting one to false restores the former lenient parsing for legacy clients. The OX properties are authoritative and take precedence over the corresponding Grizzly JVM system properties.

SCR-1747

Summary: Migrated JAX-RS from Jersey 2.17 to Jersey 3.1.x (jakarta.ws.rs)

Effective: 8.52.190 and later

Migrates the middleware JAX-RS stack from Jersey 2.17 (javax.ws.rs) to Jersey 3.1.3 (jakarta.ws.rs) as part of the Jakarta EE / Servlet 6 migration. The target platform drops Jersey 2.17, HK2 2.4 and the eclipsesource OSGi JAX-RS connector and gains Jersey 3.1.3, HK2 3.0.5, osgi-resource-locator 1.0.3 and the Jakarta APIs (ws.rs 3.1.0, inject 2.0.1, annotation 2.1.1, validation 3.0.2); javax.ws.rs-api 2.0.1 is retained so external and legacy consumers such as Guard still resolve the old API at runtime. Resources and providers are no longer published via the eclipsesource connector but by a new in-house publisher in com.openexchange.rest.services that tracks @Path/@Provider OSGi services and mounts them on a central Jersey ServletContainer. All in-house consumers and the downstream repositories (guard, usm, cloud-plugins, plugins, exchange-interop, customer bundles) were migrated in lockstep. REST endpoint paths and request/response contracts are unchanged; no configuration changes.

SCR-1746

Summary: Upgraded third-party libraries

Effective: 8.52.190 and later

Upgrades third-party OSGi bundles in the target platform (com.openexchange.bundles), among them angus-activation 2.0.3, Apache Mime4j 0.8.14, commons-validator 1.10.1, dnsjava 3.6.5, jakarta.activation-api 2.1.4, jakarta.json-api 2.1.3, jakarta.xml.bind-api 4.0.5, jaxb-osgi 4.0.9, jctools-core 4.0.6, jsoup 1.22.2, openjson 1.0.13, slf4j and its bridges 2.0.18, logback 1.5.37, equinox.console 1.4.1100, ASM 9.10.1, Jackson 2.22.x, commons-codec 1.22.0, commons-io 2.22.0, commons-net 3.13.0, gson 2.14.0, javassist 3.32.0-GA, joda-time 2.14.2, mysql-connector-j 9.7.0, protobuf-java 4.35.1 and stax2-api 4.3.0. The encapsulated libraries of the PDE bundles are upgraded as well: com.google.guava (Guava 33.6.0-jre, Caffeine 3.2.4), com.amazonaws (AWS SDK for Java v1 1.12.797, its last release), com.hazelcast (5.3.8), com.nimbus (oauth2-oidc-sdk 11.37.2), com.eatthepath.pushy (0.15.6) plus a same-major patch/minor batch across further library-enclosing bundles (unboundid-ldapsdk, u2flib, cbor/lombok, zxing, minimal-json, jcodec, woodstox-core, metadata-extractor, ipaddress, dropwizard metrics, opencsv, jgettext, junidecode, swagger-annotations, cassandra-driver, cryptacular/velocity). No new or removed embedded dependencies. Excluded as not drop-in and tracked separately: BouncyCastle 1.79 to 1.84, Grizzly 5.0.1 to 5.0.2 and Micrometer 1.10/1.5 to 1.17.

API - HTTP-API

SCR-1776

Summary: New HTTP API endpoint "PUT /proxy?action=getUris"

Effective: 8.52.190 and later

A new bundle com.openexchange.proxy.json adds an HTTP API for the proxy servlet: the module "proxy" with the single action "getUris". PUT /proxy?action=getUris takes a request body of the form {"urls": ["url1", "url2", ...]} and returns, under the standard data envelope, a hash mapping each supplied URL to its generated proxy URI. The proxy URIs are generated via the ProxyRegistry, routing external-resource access through com.openexchange.proxy.servlet. URLs are resolved via com.openexchange.java.URIs.toUriIfAbsoluteAndSupported and must therefore be absolute with a supported scheme, as for the existing ProxyRegistry callers. The generated registrations carry the NoAuthForRemoteRestriction, so neither basic authentication nor internal addresses are permitted. The action requires a session; the OAuth scope is read_proxy.

SCR-1748

Summary: New HTTP-API mail actions get_ref / get_ref_attachment to load mails referenced from PIM attachments or Infostore files

Effective: 8.52.190 and later

Two new HTTP-API actions on the mail module load and render a mail that does not reside in a mailbox but is referenced from another module - as an attachment of a PIM object (calendar event, contact, task) or as an Infostore file. PUT|GET /mail?action=get_ref loads the referenced mail and returns it like action=get, PUT|GET /mail?action=get_ref_attachment streams a binary sub-part selected via sequenceId, analogous to action=attachment. The reference is a JSON object with the slots type (calendar, contacts, tasks or infostore), folder, object, attachment and version, supplied either as the request body (PUT) or as a single URL-encoded ref query parameter (GET), so it can never collide with the mail module's reserved parameters; calendar, contacts and tasks use folder plus object plus attachment, infostore uses object plus an optional version. A new interface bundle com.openexchange.mail.stream.provider introduces MailStreamProvider, contributed per module via the OSGi service registry and returning a MailStream whose RFC822 content is parsed centrally by the mail module; providers ship for tasks, contacts and Infostore in com.openexchange.server and for calendar in com.openexchange.chronos.json. The change is purely additive - existing actions and their contracts are unchanged, access checks stay with the underlying module storage, and a referenced item that is not a valid RFC822 message yields a NOT_A_MAIL error.

SCR-1739

Summary: Cross-Context Principal Representation Over WebDAV / CalDAV / CardDAV

Effective: 8.52.190 and later

A foreign-context principal is addressable over the DAV protocols by a qualified principal path; foreign grants are handled consistently in DAV ACL/sharing. Additive (host-context principals unchanged).

  • Qualified principal URLs /principals/users/<id>@<contextId> (resp. groups), via Entity.toFormattedString() (com.openexchange.dav.mixins.PrincipalURL). UserPrincipalCollection / GroupPrincipalCollection parse the qualified leaf and resolve a foreign principal only if the cross-context authority permits a liaison from the session user to the target context (CrossContextAuthorityProvider.isLiaisonPermitted); a disallowed context is reported as 404 (invisible, never confirmed). The foreign principal resource carries a reduced property set — identity + addressing for a user (display name, e-mail, calendar-user-address, resource id), identity only for a group — dropping the context-local navigational properties (calendar / addressbook home sets, group membership) as not meaningful across the context boundary.
  • Folder-sharing invite property: the CalDAV calendar invite (<CS:invite>, com.openexchange.caldav.mixins.Invite) includes foreign-context sharees — each as a context-qualified principal href (/principals/users/<id>@<contextId>) with a display name from the permission's EntityInfo (host-context user/group lookup can't resolve a foreign principal). The base WebDAV folder invite (<D:sharee>, com.openexchange.dav.mixins.Invite) instead omits foreign-context grants — it emits only id-only local principal paths, which can't address a foreign principal (public folders emit no sharees at all).
  • CalDAV: a foreign-context calendar owner/organizer is surfaced via its mail URI only (no bare entity); context is compared alongside the id when matching the acting user.

See the feature documentation for further details.

SCR-1738

Summary: Cross-Context Deputy via Qualified Identifiers (Deputy HTTP API)

Effective: 8.52.190 and later

The deputy HTTP API can appoint and represent a deputy or grantor in another context. Additive.

  • DeputyPermission.identifier (request) — <id>@<contextId> or mailto:<email>; supersedes userId when present.
  • GrantedDeputyPermission (response) — identifier (deputy) and grantorIdentifier (grantor) as <userId>@<contextId>; the bare userId/grantorId are not meaningful for a foreign entity.
  • GrantedDeputyPermission.entityInfo (response) — pre-resolved entity information (display name, e-mail, ...) for the deputy entity, so a client can render a (possibly foreign-context) deputy it cannot resolve on its own; mirrors the shared-account entityInfo block. Absent for a group deputy; for a foreign entity the numeric entity is omitted and only the qualified identifier is carried.
  • GrantedDeputyPermission.grantorEntityInfo (response; action=reverse) — the counterpart of entityInfo for the granting user, so the deputy can render a (possibly foreign-context) grantor.
  • Available-deputy-modules action: new optional extended=true returns objects with a crossContext flag per module (true only for mail/calendar when the user is in a trust zone and the feature is enabled); the default array form is unchanged.

See the HTTP API documentation and the Deputy permissions documentation for further details.

SCR-1737

Summary: New Read-Only Contact Field Exposing the Cross-Context Qualified Identifier

Effective: 8.52.190 and later

New read-only contact field surfacing a contact's internal user as a qualified principal identifier, for direct use as a permission identifier.

  • Column 625 (Contact.USER_IDENTIFIER); JSON field user_identifier (ContactFields.USER_IDENTIFIER).
  • Value: <userId>@<contextId> (opaque, round-tripped verbatim). Virtual / read-only, not persisted (no DB change); emitted only when the column is requested and both ids are present. For a foreign entity the numeric INTERNAL_USERID (524) is masked.

See the HTTP API documentation for further details.

SCR-1736

Summary: Folder Permissions Accept and Return Cross-Context Principal Identifiers

Effective: 8.52.190 and later

A folder permission may address a foreign-context recipient via the long-standing identifier field instead of the numeric entity. Additive.

  • Write: identifier = <id>@<contextId> (e.g. 3@1337) or mailto:<email> (resolved via a PrincipalUriResolver). A foreign principal is admitted only if the cross-context authority permits, else FLD-1053 (PERMISSION_DENIED_CROSS_CONTEXT).
  • Read: identifier is always present (qualified form); the numeric entity is written only for local principals (masked for foreign). Extended folder/file permissions surface a foreign principal via identifier/EntityInfo and do not anonymize it under a guest session.
  • The same identifier semantics are documented on the Drive folder-permission schemas (Drive is not itself a cross-context target).
{ "entity": 42, "bits": 4 }                                // internal (unchanged)
{ "identifier": "3@1337", "bits": 4 }                      // cross-context, by qualified id
{ "identifier": "mailto:bob@partner.example", "bits": 4 }  // by email

See the HTTP API documentation and the feature documentation for further details.

API - REST

SCR-1801

Summary: New Administrative REST Servlet for Querying Free/Busy Data

Effective: 8.52.190 and later

New administrative REST service for querying the free/busy data of a context's users, without acting on behalf of a session user. Base /preliminary/chronos/v1/freebusy; HTTP Basic auth (admin); preliminary. OpenAPI: http-api/rest_api/paths/chronos/v1/freebusy/.

Serves consumers that need to know when a user is busy, but must not learn why - the events behind a busy period are never serialized, not even in their anonymized form. Intended for service-to-service queries within a deployment, e.g. a booking service performing a calendar conflict check while deriving bookable slots.

  • GET /freebusy/{context} - free/busy periods of any number of users at once, each referenced either by its numerical internal user identifier or by one of its email addresses (including aliases); yields one result per requested user, in request order. Resources and rooms can be queried alongside the users by passing their email address.
  • GET /freebusy/{context}/{user} - convenience variant for a single user referenced by its identifier, yielding the free/busy result directly instead of wrapping it into an array.

Both accept the time range as UTC timestamp in milliseconds, as ISO-8601 date or date/time, or in the iCalendar notation also used by the HTTP API, and merge overlapping periods by default (merge=false yields one period per appointment). The JSON model matches the one of the client-facing chronos?action=freebusy request, minus the event details.

The lookup is performed per user, so a user that cannot be served is reported with a warning instead of its periods rather than failing the whole request. The effective freeBusyVisibility of the queried users is honored, i.e. users that restricted their free/busy data to their own context or hid it entirely are reported without any periods.

Unlike the internet free/busy servlet at /servlet/webdav.freebusy - the other session-less way to obtain free/busy data - this service answers in JSON instead of iCalendar, accepts a batch of users per request, and is protected by HTTP Basic Authentication instead of relying on not being reachable from the outside. It also does not require com.openexchange.calendar.enableInternetFreeBusy / com.openexchange.calendar.publishInternetFreeBusy to be set.

See the general documentation, as well as the REST API documentation for further details.

SCR-1740

Summary: New Administrative REST Endpoints for Cross-Context Liaison Audit and Purge

Effective: 8.52.190 and later

New administrative REST service for cross-context liaison audit + on-demand purge. Base /preliminary/crosscontext/v1; HTTP Basic auth (admin); preliminary. OpenAPI: http-api/rest_api/paths/crosscontext/v1/.

  • GET /inbound/{context} and GET /inbound/{context}/{user} — what a principal received (per-module liaisons, trust zones, mail-share owners).
  • DELETE /inbound/{context}/{user} — purge received access; filters from / owner / module; unconditional operator override (does not consult the authority).
  • GET /outbound/{context}/{user} and DELETE /outbound/{context}/{user} — what a principal granted out, and purge it; filters to / module.

See the REST API documentation and the feature documentation (inbound/outbound audit and on-demand purge) for further details.

API - RMI

SCR-1741

Summary: Cross-Context Deputy in the Admin RMI Provisioning API

Effective: 8.52.190 and later

The admin deputy provisioning over RMI (com.openexchange.admin.rmi; impl com.openexchange.admin.rmi.impl.OXDeputyPermissions) can appoint/represent a deputy in another context. Additive; an absent / 0 context = same context. A cross-context deputy is admitted only if the authority permits.

Data objects (com.openexchange.admin.rmi.dataobjects):

  • DeputyPermission — qualified Entity entity (id + context).
  • DeputyPermissionDescription — entityContextId (with setEntityContextId / removeEntityContextId / isEntityContextSet flag accessors).
  • Granter — qualified Entity entity; equals / compareTo consider the context.

On top of RMI, the gRPC provisioning layer carries the same cross-context support — generated stubs (com.openexchange.grpc.generated, consumed as a binary artifact) plus DeputyPermissionConverter (com.openexchange.provisioning.grpc.common). In deputy.proto: additive scalar context fields DeputyPermission.entity_context_id, Granter.context_id, DeputyPermissionDescription.entityContextId + EntityContextIdSet (0 = same context); plus the GrantedDeputyPermissions.granted map key retyped map<int32, …> -> map<string, …> (qualified <id>@<contextId>) — the one wire-breaking change (ListReverseDeputyPermissions response). The DeputyPermissionConverter carries the entity context across the boundary; the gRPC server and client implementations delegate to it.

See the Deputy permissions documentation for further details.

API - SOAP

SCR-1798

Summary: Provision per-account spam handler for secondary accounts (functional mailboxes)

Effective: 8.52.190 and later

For non-primary accounts - secondary "functional" mailboxes and external accounts - the spam handler used by "Mark as Spam" is now resolved from the account's own configured spam handler name instead of being unconditionally disabled. It falls back to the NoSpamHandler when no handler name (or the fallback one) is set, so spam handling for such accounts is opt-in and enabled via provisioning; the primary account behavior is unchanged. To make this usable, secondary account provisioning was extended to carry the spam handler: a new field on the RMI AccountData data object, on the SOAP AccountData, AccountDataOnCreate, AccountDataUpdate and Account objects and their mappings, INSERT/UPDATE in the MySQL storage, the new CLI option --spam-handler for createsecondaryaccount and updatesecondaryaccount, and a spam-handler column in the listsecondaryaccount output. Without an explicitly provisioned spam handler the default stays NoSpamHandler, so there is no behavior change. Related: /appsuite/support#1552.

SCR-1742

Summary: Cross-Context Deputy in the Admin SOAP Provisioning API

Effective: 8.52.190 and later

The admin deputy provisioning over SOAP (com.openexchange.admin.soap.deputy; OXDeputyPermissionsServicePortTypeImpl) can appoint/represent a deputy in another context. Additive; context fields default to same-context. A cross-context deputy is admitted only if the authority permits.

Data objects (com.openexchange.admin.soap.deputy.dataobjects):

  • DeputyPermission — contextId (the deputy entity's context).
  • ActiveDeputyPermission / GrantedDeputyPermission — entityContextId, contextId, granterContextId.

See the Deputy permissions documentation (cross-context SOAP grant example) for further details.

Behavioral Changes

SCR-1759

Summary: Seal proxy registration URLs via ObfuscatorService instead of static DES key

Effective: 8.52.190 and later

The stateless proxy registration URLs produced for external image proxying (com.openexchange.proxy.servlet) carry the full registration - target URI plus restrictions - and were encrypted with a static DES key derived from the string "ox-proxy", which is present in the public AGPL source. Any authenticated user could therefore forge valid proxy URLs, for instance stripping restrictions to turn the middleware into a generic fetch proxy or aiming at internal endpoints (SSRF surface). Full-registration content is now sealed via the ObfuscatorService, using a per-installation secret and authenticated AES/GCM, so only the server can produce valid proxy URLs. A new wire-level encoding mode "sealed" (mode byte 2) is emitted; the legacy static-DES "object" format (mode byte 1) is still accepted on decoding for the rolling-upgrade transition and can be dropped in a later release. No configuration change - the com.openexchange.proxy.encoding semantics are unchanged and only the internal sealing of the full-registration payload changed - but ObfuscatorService is now a required service of the bundle. This is hardening; session enforcement and response restrictions already gated the endpoint.

SCR-1743

Summary: Cross-Context Sharing Access-Control Behavior

Effective: 8.52.190 and later

A user in one context can grant a user in another context access to a folder, mail folder, or deputy role within one deployment.

  • Deny-by-default trust zones — admitted only if the sharing user's and target context's com.openexchange.crosscontext.trustZones tags intersect; opt-in per deployment (global = legacy anyone-with-anyone).
  • Hard-deny at grant resolution — a foreign identifier resolving to another context is admitted only if the authority permits, else FLD-1053; enforced centrally (folder resolver, deputy service, admin RMI). Same-context / no-authority-registered unaffected.
  • Public read-only — a foreign grantee may receive up to author on a personal/shared calendar folder, but only read-only on a public folder.
  • Admission-only — checked at grant time, never re-checked on read; an admitted grant survives a later zone change until explicitly revoked. No operator switch (com.openexchange.crosscontext.reenforceOnRead removed; CrossContextAuthorityProvider.isReadReenforcementEnabled hard-wired false; dormant code retained).
  • Mail same-server — requires com.openexchange.mail.crossContextPermissions (default false) and, when com.openexchange.mail.crossContextRequireSameServer (default true), the same mail server; an explicit revoke removes the IMAP ACL via best-effort doveadm.
  • Deputy — a revoke/purge revokes the foreign reverse permission (cascading to projected calendar/mail shares; deputy liaisons purged first).

See the feature documentation for further details.

CLT

SCR-1758

Summary: New Command-Line Tool claimfolderadmin to Claim/Elevate a Folder Administrator on Public Folders

Effective: 8.52.190 and later

New command-line tool claimfolderadmin that grants or elevates a specific user to folder administrator on public folders - the only folder type that permits more than one administrator (FolderObject.PUBLIC; private and shared folders are restricted to a single owner-admin). It targets the case where a deleted user's data was reassigned to a user that cannot log in (e.g. the context administrator): another user can then take over administration of the affected public folders. The operation is additive - existing administrators are kept.

The tool is invoked as follows:

claimfolderadmin -c <contextId> -u <userId>
                 (-f <folderId> | --from-user <sourceUserId>)
                 -A <admin> -P <password>
                 [-p <RMI-Port>] [-s <RMI-Server>]
  • -c/--context - the target context
  • -u/--user - the user that shall become folder administrator
  • -f/--folder - a single public folder to claim
  • --from-user - bulk mode: claim every public folder currently administered by this source user (mutually exclusive with -f)

Authenticates with the context administrator credentials (-A/-P).

The claim operation behaves as follows:

  • Grants full administrative rights plus the folder-admin flag; an existing permission of the user is elevated in place (no duplicate entry). Additive - existing administrators are retained.
  • Only FolderObject.PUBLIC folders are accepted; private/shared folders are rejected (OXFolderExceptionCode.NOT_A_PUBLIC_FOLDER).
  • Bulk mode (--from-user) is scoped to the public folder subtrees - below SYSTEM_PUBLIC_FOLDER_ID (public groupware folders) and SYSTEM_PUBLIC_INFOSTORE_FOLDER_ID (public InfoStore folders); the source user's personal InfoStore home folder and its subfolders are excluded.
  • Idempotent; logs one INFO line per invocation listing the claimed folder identifiers and invalidates the affected folder caches.

Backed by a new RMI service ClaimFolderAdminRMIService registered by the groupware server. For active-active deployments it is site-aware (wrapper SiteAwareClaimFolderAdmin), routing a call to the write-active site owning the target context - plugging into the infrastructure of SCR-1697. Inter-site forwarding uses a new gRPC service ClaimFolderAdminService (client + server) defined in grpc-api/proto_jar/protos/claimfolderadmin.proto.

Documented in documentation/command_line_tools/miscellaneous/claimfolderadmin.md.

Configuration

SCR-1799

Summary: New property to run the Grizzly engine as WebSocket side-car alongside the Jetty engine

Effective: 8.52.190 and later

With the optional Jetty HTTP engine enabled (com.openexchange.http.jetty.enabled=true), the Grizzly engine can now be started in a WebSocket side-car mode: a single network listener on a dedicated port serves nothing but WebSocket upgrades for applications registered through the Grizzly-typed WebApplicationService, while Jetty serves regular HTTP(S). This allows deployments that still ship Grizzly-typed WebSocket applications to enable the Jetty engine without migrating them first. The mode is controlled by the new property com.openexchange.http.grizzly.websocketSidecarPort in grizzly.properties, default 0, neither reloadable nor config-cascade aware and evaluated once during server start-up. It is only effective while the Jetty engine is enabled; a value of zero or less disables the side-car and leaves the Grizzly engine fully passive, which is the previous behavior and therefore a no-op default for existing deployments. It requires com.openexchange.http.grizzly.hasWebSocketsEnabled=true, otherwise the side-car start-up is skipped with a warning, and the port is opened deferred once server start-up completed. The side-car provides no HttpService, no Comet and no liveness facilities - WebSocket upgrades only. Clients are unaffected and keep their WebSocket URLs; only the reverse proxy or ingress has to route the affected WebSocket context paths to the side-car port. Note that 8010 is the default HTTPS connector port, so pick a free port such as 8011. See the new administration article "Switching the HTTP Engine (Grizzly to Jetty)" for the complete runbook including routing examples.

SCR-1797

Summary: New config properties for OAuth token exchange additional parameters (scheduled/snoozed mail)

Effective: 8.52.190 and later

Two new lean configuration properties allow passing additional request parameters when performing the OAuth 2.0 Token Exchange (RFC 8693) used for background delivery of scheduled and snoozed mails: com.openexchange.mail.scheduled.oauth.tokenExchange.additionalParameters and com.openexchange.mail.snoozed.oauth.tokenExchange.additionalParameters, both defaulting to empty and both config-cascade aware and reloadable. The parameters are appended to the POST /token request; the primary use case is selecting the token exchange policy at the OAuth server, for instance the IONOS ID Server, via a usecase parameter that determines allowed scopes, allowed audiences and the issued-token lifetime. The format is a single key=value pair, with multiple pairs separated by &; a value-less flag is accepted and serialized as flag=. The properties are only effective when the corresponding ...oauth.tokenExchange property is enabled, and being empty by default they cause no behavior change for existing setups.

SCR-1793

Summary: Redis connector: per-node client name, max. connection lifetime, deterministic shutdown

Effective: 8.52.190 and later

Hardening of the Redis connector against stale / orphaned connected clients.

New configuration option:

  • com.openexchange.redis.connection.pool.maxLifetimeSeconds Maximum lifetime in seconds of a pooled Redis connection. Once a connection exceeds this age it is proactively recycled by the connection-pool cleaner as soon as it becomes idle, regardless of usage; this applies to both the shared and the dedicated pool. Acts as defense-in-depth against slowly accumulating or long-lived stale connections that TCP keepalive cannot reap (a live-but-idle connection is never detected as dead). A value of 0 (zero) disables max. lifetime recycling. Default 3600 (one hour). Not reloadable, not config.cascade aware. Package: open-xchange-core.

Behavioral changes (no configuration):

  • Client name: the announced Redis client name now includes the local host / pod name (e.g. Open-Xchange-Redis-Connector-v8.53.0-<host>), so connections become attributable per node via Redis CLIENT LIST. This is what lets operators tell restart orphans (dead pod addresses) apart from live-node connections.
  • Deterministic shutdown: the shared connection pool now closes its connections synchronously on shutdown, so Redis reclaims the clients immediately on a graceful (rolling) restart instead of leaving them as ghosts.

SCR-1788

Summary: Increased defaults for the client-side prepared statement cache (prepStmtCacheSize, prepStmtCacheSqlLimit)

Effective: 8.52.190 and later

The defaults of the MySQL Connector/J client-side prepared statement cache are raised, both in dbconnector.yaml and in the built-in fallback: prepStmtCacheSize from 250 to 1024 and prepStmtCacheSqlLimit from 2048 to 8192. JFR profiles under load attributed roughly 2.5% of CPU to Connection.prepareStatement, dominated by Connector/J query re-parsing plus visible LRU eviction churn in the statement cache: the middleware's dynamically built statements with mapped column lists and IN clauses exceed the previous 2048-character limit and were silently never cached, and the statement variety overflows a 250-entry LRU per connection. The cache holds parsed client-side statement metadata per pooled connection, so the increase amounts to low single-digit MB per connection pool under full variety. There is no behavioral change - the cache keys on the SQL text only and stays valid across schema changes, and useServerPrepStmts remains false - and deployments overriding these keys in dbconnector.yaml keep their configured values.

SCR-1783

Summary: Removed properties "com.openexchange.push.dovecot.stateless" and "com.openexchange.push.dovecot.clusterLock"

Effective: 8.52.190 and later

The stateful Dovecot Push implementation, which kept per-node listener bookkeeping guarded by a cluster lock, has been removed. The stateless implementation - the default since 7.10.4, more robust and requiring no cluster-wide locking - is the only mode now. Consequently the lean configuration properties com.openexchange.push.dovecot.stateless (default true) and com.openexchange.push.dovecot.clusterLock (default hz, only effective with stateless=false) are no longer evaluated and have been removed. The middleware always behaves as if stateless=true was configured, so deployments still setting these properties can simply drop them; setting them has no effect anymore. All other Dovecot Push properties (enabled, preferDoveadmForMetadata, unregisterAfterDelete) are unchanged.

SCR-1782

Summary: New configuration property for cleartext HTTP/2 (h2c) on the Jetty HTTP engine

Effective: 8.52.190 and later

The optional Jetty-based HTTP engine introduced with SCR-1756 gains optional support for cleartext HTTP/2 (h2c) on the HTTP network listener, controlled by the new lean property com.openexchange.http.jetty.http2.enabled (Boolean, default false). It is a server-scope setting evaluated once during server start-up, neither config-cascade aware nor reloadable, and read from the Jetty namespace exclusively since the Grizzly engine does not support HTTP/2. When enabled, h2c is offered both via the HTTP/1.1 upgrade mechanism and via prior knowledge, while HTTP/1.1 requests keep being served on the same listener. The property defaults to disabled because HTTP/2-capable clients - for instance the JDK HTTP client used by SOAP and REST integrations - pro-actively send the Upgrade: h2c header and would actually switch, so it should be enabled deliberately once load-balancer h2c upstream support and client compatibility are verified. The HTTPS listener is unaffected: HTTP/2 over TLS (ALPN) is not offered, since in the standard deployment TLS terminates at the load balancer.

SCR-1781

Summary: New configuration properties for Jetty HTTP engine metrics and access-log rotation

Effective: 8.52.190 and later

The optional Jetty-based HTTP engine introduced with SCR-1756 gains Micrometer metrics and access-log rotation through three new lean properties, all of them server-scope settings evaluated once during server start-up and therefore neither config-cascade aware nor reloadable. com.openexchange.http.jetty.metrics.enabled (Boolean, default true, read from the Jetty namespace exclusively) registers the engine's metrics with the Micrometer registry under the appsuite.jetty.* name space: worker thread pool gauges, per-connector connection statistics tagged with the connector, and server-wide request statistics including responses tagged with the HTTP status class. com.openexchange.http.jetty.accesslog.rotate (default none, supported values none and daily, subject to the Grizzly-pendant fallback) rolls the access log over at local midnight and adds the yyyy_mm_dd place-holder required by Jetty unless the file name already contains one; a value of hourly is treated as daily. com.openexchange.http.jetty.accesslog.retainDays (default 31, Jetty namespace only) bounds how long rotated files are kept. With this change the Grizzly-only property accesslog.rotate listed in SCR-1756 gains a Jetty pendant, while .synchronous and .statusThreshold remain without one. There is no behavioral change for existing deployments.

SCR-1778

Summary: Mandatory 'objectid' mapping for LDAP contacts providers

Effective: 8.52.190 and later

The objectid entry in mapping sections of contacts-provider-ldap-mappings.yml is now treated as mandatory: LDAP contacts provider configurations referencing a set of mappings without it are rejected during initialization with a configuration error (the affected provider section is skipped and logged accordingly, other providers are not affected). Previously, a DN-based fallback was applied, which however only covered the conversion of search results - the resulting identifiers could not be resolved back to entries, so that retrieving single contacts failed with a misleading OX-0001 "Object not found. OBJECT_ID", and search filters on the object id are generally not expressible against entry DNs. Failing early with an actionable error replaces these runtime errors. Deployments relying on the fallback need to configure an objectid mapping, e.g. entryUUID (OpenLDAP) or objectGUID;guid (Active Directory), which are both stable across entry renames and moves; the shipped mapping template was updated accordingly.

See the LDAP contacts provider documentation for further details.

SCR-1761

Summary: New Helm value javaOpts.compactObjectHeaders in core-mw chart

Effective: 8.52.190 and later

New boolean Helm value javaOpts.compactObjectHeaders (default true) in the core-mw chart prepends -XX:+UseCompactObjectHeaders (JEP 519) to the JAVA_OPTS_OTHER environment variable independently of a custom javaOpts.other, whose default is now empty and which remains available for extra verbatim JVM options. Previously the flag lived in the default of javaOpts.other, and since Helm replaces scalar values instead of merging them, any installation overriding that value - for instance to inject a Java agent - silently lost the flag. Toggle-controlled flags are no longer appended twice: -XX:+UseCompactObjectHeaders, -XX:+UseZGC and -XX:ZUncommitDelay are skipped when javaOpts.other already mentions them, so an explicit -XX:-UseCompactObjectHeaders opt-out is left untouched. Installations overriding javaOpts.other now run with Compact Object Headers enabled after the upgrade; set javaOpts.compactObjectHeaders: false to keep the old behavior. Shipped with chart version 6.23.1.

SCR-1757

Summary: New property "com.openexchange.mail.wellFormedHtmlTruncateOnRaw"

Effective: 8.52.190 and later

The max_size parameter of the HTTP API's mail?action=get call is honored for view=raw by hard-truncating the emitted message content. The new lean property com.openexchange.mail.wellFormedHtmlTruncateOnRaw (default true; reloadable and config-cascade aware) controls the markup-aware truncation of HTML bodies that lets clients receive reasonably well-formed markup. If enabled, the truncation cut never splits a tag, comment or character entity, and elements left open by the cut are closed by appending their closing tags, so the returned markup may slightly exceed max_size by those closing tags. If disabled, HTML content is hard-truncated at exactly max_size characters.

SCR-1756

Summary: Configuration properties for the optional Jetty-based HTTP engine

Effective: 8.52.190 and later

The middleware gains an optional, alternative HTTP engine based on Eclipse Jetty 12.1 in the new bundle com.openexchange.http.jetty; the Grizzly-based engine remains the default. The engine is selected per deployment via the new lean property com.openexchange.http.jetty.enabled (Boolean, default false): when enabled, the Jetty engine serves HTTP(S) and the Grizzly engine does not start. Unless stated otherwise, every property below is a server-scope setting evaluated once during server start-up - not config-cascade aware and not reloadable. Engine-neutral properties keep applying unchanged to both engines with the same keys, defaults and semantics: com.openexchange.connector.* (networkListenerHost/-Port, networkSslListenerPort, livenessPort, awaitShutDownSeconds, maxRequestParameters), com.openexchange.server.* (considerXForwards, knownProxies, forHeader, protocolHeader, portHeader, checkTrackingIdInRequestParameters), com.openexchange.servlet.* (echoHeaderName, useRobotsMetaTag/robotsMetaTag, contentSecurityPolicy, maxInactiveInterval, maxFormPostSize, maxBodySize), com.openexchange.cookie.* (ttl, httpOnly, sameSiteValue), com.openexchange.forceHTTPS, com.openexchange.log.extensionHttpHeaders and com.openexchange.requestwatcher.isEnabled. Grizzly-specific properties received equally named com.openexchange.http.jetty.* pendants sharing the same defaults, which now live in code rather than in grizzly.properties: hasJMXEnabled, hasWebSocketsEnabled, wsTimeoutMillis, doAbsoluteRedirect, maxHttpHeaderSize, hasSSLEnabled, keystorePath/-Id/-Password, enabledCipherSuites, maxNumberOfConcurrentRequests, readTimeoutMillis, selectorRunnersCount, tcpNoDelay, sessionExpiryCheckInterval, virtualThreadsEnabled, livenessEnabled, addServerVersion, accesslog.file/.format, strictHeaderNameValidation and strictHeaderValueValidation. An unset Jetty key falls back to the equally named Grizzly pendant before applying the shared default, so an existing deployment keeps its tuning after merely enabling the Jetty engine; selectorRunnersCount is the only exception and is read from the Jetty namespace exclusively. Note that the Jetty engine exposes the standard jakarta.websocket.server.ServerContainer (JSR 356) instead of the Grizzly-typed WebApplicationService. Additionally new is the lean property com.openexchange.drive.events.asyncLongPolling.enabled (default true), which serves Drive event long polling through the standard servlet asynchronous API so suspended listen requests no longer consume a server thread; an installed Grizzly Comet handler still takes precedence. Grizzly-specific properties without a Jetty pendant keep working for Grizzly but have no effect under Jetty: hasCometEnabled, com.openexchange.connector.shutdownFast, maxQueryStringSize, writeTimeoutMillis, keepAlive, minWriteBufferSize, sessionUnjoinedThreshold, removeNonAuthenticatedSessions, supportHierachicalLookupOnNotFound and accesslog.synchronous/.statusThreshold/.timezone. A follow-up review of the engine, contained in 8.52.202 and later as well as in 8.53, adds the property com.openexchange.http.jetty.hasAccessLogEnabled (default true, with a Grizzly pendant) and changes existing semantics: strictHeaderNameValidation=false no longer relaxes anything and strictHeaderValueValidation=false no longer permits folded field values or field lines without a colon, since those are message framing and a request smuggling primitive; a non-positive com.openexchange.connector.awaitShutDownSeconds is now treated as a long but bounded grace period capped at one hour instead of disabling the graceful shut-down. In the same releases the liveness listener is confined to its probe end-point (/live answers 200 for GET and HEAD, every other path and method is refused), TRACE is answered with 405 before it reaches the servlets, a non-positive maxFormPostSize or maxRequestParameters means unlimited as documented, and com.openexchange.servlet.maxActiveSessions is enforced by the Jetty engine as well. Finally, the open-xchange-jetty package no longer declares Provides: open-xchange-httpservice - it is an add-on to be installed alongside open-xchange-grizzly, which keeps the rollback a configuration change instead of a package operation - and its settings belong in an administrator-created jetty.properties, since the bundle ships no configuration file of its own.

SCR-1735

Summary: New Configuration Options for Cross-Context Sharing

Effective: 8.52.190 and later

New properties; all reloadable and config.cascade aware.

  • com.openexchange.crosscontext.trustZones — comma-separated trust-zone tags; a grant is admitted only if the sharing user's and target context's tag sets intersect. Source per-user, target per-context. Default empty (deny); global at server scope = legacy anyone-with-anyone.
  • com.openexchange.crosscontext.tryPromoteGuests — promote an email-only guest permission to a cross-context permission when it resolves to an internal user in another context and the authority admits. Default true.
  • com.openexchange.mail.crossContextRequireSameServer — reject a cross-context mail grant unless the grantee's mailbox is on the same mail server (fails open if indeterminate). Default true.
  • com.openexchange.calendar.crosscontext.enabled — enable the cross-context calendar provider, which surfaces calendars shared from other contexts as ordinary calendar accounts (one account per foreign context, over the HTTP API and CalDAV). Default true.

(Mail master switch com.openexchange.mail.crossContextPermissions, default false, recorded under SCR-1574; also subject to the trust-zone gate.)

See the property documentation and the feature documentation for further details.

Database

SCR-1734

Summary: Deputy Storage Table Qualifies the Deputy Entity With Its Context

Effective: 8.52.190 and later

Update Task com.openexchange.deputy.impl.groupware.DeputyStorageAddEntityContextColumnTask

The deputy table gains entityCid (INT4 UNSIGNED NOT NULL DEFAULT 0; 0 = grantor's context) so a deputy may live in another context. Behavior-neutral for existing deputies.

Fresh schemas: com.openexchange.deputy.impl.groupware.DeputyStorageCreateTableService. Existing schemas: com.openexchange.deputy.impl.groupware.DeputyStorageAddEntityContextColumnTask (idempotent; depends on the deputy create-table task).

See the Deputy permissions documentation for further details.

SCR-1733

Summary: Restructured the Folder-Permission Primary Key to Include the Context Column

Effective: 8.52.190 and later

Update Task com.openexchange.groupware.update.tasks.RestructureFolderPermissionPrimaryKeyUpdateTask

Building on the new context column (previous SCR), the PK (and the principal index where present) is extended to include it, so cross-context and same-context permission rows coexist without collision.

  • oxfolder_permissions / del_oxfolder_permissions: PK (cid, fuid, permission_cid, permission_id, system); index principal (cid, permission_cid, permission_id, fuid).
  • virtualPermission / virtualBackupPermission: PK (cid, tree, user, folderId, entityCid, entity).

Each ALTER rewrites the InnoDB clustered index (slow on large tables). Existing schemas: com.openexchange.groupware.update.tasks.RestructureFolderPermissionPrimaryKeyUpdateTask (idempotent; depends on AddPermissionContextIdToFolderPermissionTableUpdateTask). Fresh schemas: the create-table services above.

See the feature documentation for further details.

SCR-1732

Summary: Added a Permission-Context Column to the Folder-Permission Tables

Effective: 8.52.190 and later

Update Task com.openexchange.groupware.update.tasks.AddPermissionContextIdToFolderPermissionTableUpdateTask

The folder-permission tables gain a context-qualifier column (INT4 UNSIGNED NOT NULL DEFAULT 0; 0 = the row's own context). Behavior-neutral for existing rows. (PK restructure is the next SCR.)

  • oxfolder_permissions, del_oxfolder_permissions -> permission_cid
  • virtualPermission, virtualBackupPermission -> entityCid

Fresh schemas: com.openexchange.admin.mysql.CreateOXFolderTables / CreateVirtualFolderTables. Existing schemas: com.openexchange.groupware.update.tasks.AddPermissionContextIdToFolderPermissionTableUpdateTask (idempotent, no deps).

See the feature documentation for further details.

SCR-1731

Summary: Added the "xctx_liaisons" Cross-Context Liaison Registry Table and Create-Table Update Task

Effective: 8.52.190 and later

Update Task com.openexchange.crosscontext.impl.storage.rdb.groupware.CrossContextLiaisonsCreateTableTask

New per-context table xctx_liaisons in the grantee (target) context's user schema (not configdb) — a pointer index, one small row per cross-context grant.

CREATE TABLE xctx_liaisons (
  `cid` INT4 UNSIGNED NOT NULL,
  `entity` INT4 UNSIGNED NOT NULL,
  `module` INT4 UNSIGNED NOT NULL,
  `sharing_cid` INT4 UNSIGNED NOT NULL,
  `owner_entity` INT4 UNSIGNED NOT NULL DEFAULT 0,
  `type` INT4 UNSIGNED NOT NULL DEFAULT 0,
  PRIMARY KEY (`cid`, `entity`, `module`, `sharing_cid`, `owner_entity`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

cid/entity = grantee context + principal; sharing_cid = owner context; owner_entity = owning entity (0 = owner-agnostic); type = LiaisonType (0=DB_FOLDER_SHARE, 1=DEPUTY, 2=MAIL_FOLDER_SHARE). Composite PK is the natural key; no secondary indexes.

  • Fresh schemas: com.openexchange.crosscontext.impl.storage.rdb.groupware.CrossContextLiaisonsCreateTableService.
  • Existing schemas: com.openexchange.crosscontext.impl.storage.rdb.groupware.CrossContextLiaisonsCreateTableTask (UpdateTaskAdapter, no deps, idempotent).
  • Cleanup: CrossContextLiaisonsDeleteListener (context/user/group delete) + LiaisonsCleanUpExecution (DatabaseCleanUpService job, 1/day; prunes orphans, fail-safe).

See the feature documentation for further details.

Packaging/Bundles

SCR-1730

Summary: Added New Bundles for Cross-Context Sharing

Effective: 8.52.190 and later

Three new OSGi bundles, shipped in open-xchange-core (already in open-xchange-core.psf; no install-list change). Bundle-Version 8, BREE JavaSE-25.

  • com.openexchange.crosscontext — API/SPI bundle (liaison registry, authority provider, principal resolution, outbound-share + cleanup SPIs). No activator.
  • com.openexchange.crosscontext.impl — implementation (RDB storage/registry, trust-zone authority, mailto: resolver, DoveAdm mail source/retractor, reconciler, admin REST). Activator com.openexchange.crosscontext.impl.osgi.CrossContextActivator.
  • com.openexchange.chronos.provider.crosscontext — cross-context calendar provider (account reconciler, iTip conversion, incoming-scheduling listener). Activator com.openexchange.chronos.provider.crosscontext.osgi.CrossContextCalendarProviderActivator.

See the feature documentation for further details.

[8.52.0]

General

Middleware Image Migrated from Debian to Wolfi OS

Summary: The App Suite Middleware container image now builds on Wolfi OS instead of Debian Bookworm

The App Suite Middleware container image now builds on Wolfi OS instead of Debian Bookworm. The Middleware application itself is unchanged.

What's new

  • Images are signed (cosign) with SLSA v0.2 provenance and ship an SPDX SBOM.
  • CVE patches flow automatically via Renovate.
  • Image is now slightly smaller than with Debian Bookworm.
  • No package manager at runtime, moving closer to distroless.

Breaking Changes to Verify

  1. /etc/ssl/certs/java/cacerts is now 0444 (read-only). Custom truststore hooks doing cp … && keytool -import … must add chmod 0644 between the two steps.
  2. No apt-get / dpkg at runtime. Use kubectl debug or the appsuite-toolkit for in-pod investigation; installing packages live is no longer possible.
  3. MariaDB client is pinned to 11.4 LTS (no Renovate auto-bump). It is wire-compatible with MySQL 5.5+ and MariaDB 10.x+ servers.
  4. Implicit Debian tools are no longer present: which, diff, xz, wget, and the hostname binary. Customer scripts using these need POSIX alternatives (command -v for which, $HOSTNAME for hostname).
  5. The Java vendor changes from Eclipse Temurin to Wolfi OpenJDK 25 (same upstream source, identical bytecode/API). Binaries like jmap, jstack, jcmd, jstat, jinfo, and jps are no longer bundled with the runtime image. For heap dumps, thread dumps, mysqldump, and other diagnostics against a running pod, use the appsuite-toolkit which provides these operations via command-line tools or ephemeral debug container attached alongside the target pod.
  6. mysql is now a symlink to mariadb, which prints a one-time deprecation warning at invocation.

Action Items for Operators

  • Smoke-test on a non-production cluster with your existing Helm values.
  • Verify any custom hook scripts (truststore imports, CA bundles, custom CLTs) against the new image.

8.51.95

Behavioral Changes

SCR-1723

Summary: Java 25: virtual-thread HTTP worker pool and opt-in generational ZGC

Effective: 8.51.95 and later

Full admin guide: Garbage Collection and Memory Sizing

Change

The core middleware now runs on Java 25 (JDK 25 runtime). Operationally relevant defaults that change with this upgrade:

  • Virtual-thread HTTP worker pool - the Grizzly request workers run on virtual threads by default (com.openexchange.http.grizzly.virtualThreadsEnabled=true), raising in-flight request concurrency.
  • Compact Object Headers (-XX:+UseCompactObjectHeaders, JEP 519) are enabled via javaOpts.other, reducing live heap.

The garbage collector default is unchanged: G1 stays the default. Generational ZGC is available as an opt-in alternative via the Helm value javaOpts.zgc (default false); set to true it appends -XX:+UseZGC to the JVM options. (An earlier revision shipped ZGC as the default; it was reverted to opt-in before release - see "Why opt-in, not default" below.) ZGC is the only change with deployment-sizing impact, and only when enabled (see below). The worker-pool defaults that accompany the virtual-thread switch are listed at the end.

What an administrator must do

Nothing is required. G1 stays the default garbage collector, so existing memory sizing is unaffected by the JDK 25 upgrade as far as the collector is concerned.

Who should opt in to ZGC. With the MALLOC_ARENA_MAX=2 default, ZGC's former native-memory penalty is largely gone - its non-heap native sits at G1 level and the only remaining premium is the eager heap commit, which converges with G1 under a realistic live set. The load test (below) showed ZGC faster than G1 - better mean and tail latency and higher throughput - even at a modest 4G/6G pod, so ZGC is a sound choice for virtual-thread, latency-sensitive deployments generally, not just large installations. G1 remains the default and the better fit for throughput-/batch-bound workloads, very small heaps (where G1 is more CPU-efficient), and CPU-starved pods (ZGC's concurrent GC needs CPU headroom). Validate under your own load before tightening below 4G/6G - the benchmark had a small heap live set and under-exercised mail/attachment-heavy paths.

If you do opt in (javaOpts.zgc: true), size for ZGC's native-memory headroom. With MALLOC_ARENA_MAX=2 set (now a chart default - see "Why the headroom is large" below), the load-validated configuration is a 4G heap on a 6G container limit:

  • javaOpts.memory.maxHeapSize: 4G (or javaOpts.memory.maxRAMPercentage: "50")
  • resources.requests.memory: 6G and resources.limits.memory: 6G
  • MALLOC_ARENA_MAX=2 on the container env (chart default) - without it the same workload needs an 8G limit.
  • give the pod adequate CPU - concurrent GC needs headroom; do not run ZGC CPU-starved.

This was hard-validated under load (50 concurrent users, real Dovecot/Postfix): cgroup peak ~5.3G, 0 OOM, 0 restarts, no request errors. Without MALLOC_ARENA_MAX the peak is ~6.5G and a 6G limit fails (matching the earlier CI observation that 4G/6G failed). Too little memory does not surface as an OOM - it shows up as failures to open outbound IMAP/SMTP connections (mail-backend timeouts) under load, a downstream effect of the container exhausting native memory, not the mail sockets themselves. The test had a small heap live set and under-exercised mail/attachment-heavy paths, so treat the peak as a floor and keep margin - do not tighten below 6G without a heavier-mail re-test.

Why the headroom is large, and how to shrink it (load-tested 2026-06-29). Native-memory tracking under load overturns the original assumption that direct buffers dominate: direct/off-heap memory (NMT "Other") peaks at only ~0.3-0.5G and ZGC's own structures at ~80MB. The real driver of the excess is glibc malloc-arena retention (~1.2G) - the many-threaded virtual-thread middleware spawns many per-thread malloc arenas that hoard memory. Setting MALLOC_ARENA_MAX=2 (container env, now a chart default) caps this and cuts the cgroup peak from ~6.5G to ~5.3G at a 4G heap, letting ZGC fit a 6G limit. Crucially this brings ZGC's non-heap native memory down to the same level as G1 (~1.25G in both with the cap) - the only remaining difference is that ZGC eager-commits its heap while G1 right-sizes, and that gap converges under a realistic (larger) heap working set. -XX:MaxDirectMemorySize is not a useful sizing lever here (direct memory is small); it is only worth setting as an optional fast-fail cap.

(If core-mw is deployed as a subchart, the keys live under the core-mw: block.)

Returning idle memory (pay-per-used hosting). On hosting billed by actual memory use (RSS), ZGC hands idle heap back to the OS. Set javaOpts.zgcUncommitDelay (e.g. "60") to uncommit unused heap sooner than the 300s default (-XX:+ZUncommit is on by default). A 20-min soak confirmed ~2.2G returned to the OS within ~4 min of load dropping, while staying KO=0 under load. This returns heap only - glibc malloc arenas are bounded separately by MALLOC_ARENA_MAX. Trade-off: re-commit costs page faults when load returns; too short a delay churns under spiky load. If billed on the pod reservation rather than RSS, right-size the request instead. Do not throttle the heap with -XX:SoftMaxHeapSize to force a smaller footprint - a soak with SoftMaxHeapSize=2G at a 4G heap caused a severe tail regression (request timeouts, max 37.5s) by starving ZGC of allocation headroom; the idle give-back does not need it. (For very spiky, small-live-set workloads G1 reclaims even more aggressively, at a worse tail.)

Load-test results - performance and sizing

A full-stack load test (self-deployed core-mw-test umbrella chart with real Dovecot/Postfix/DB/Redis, in-cluster Gatling AppSuiteSimulation, 50 concurrent users; JDK 25, generational ZGC, 4G heap) measured ZGC against G1 at an identical 4G heap / 6G limit with MALLOC_ARENA_MAX=2, both error-free (KO=0):

  • ZGC is faster, not slower: mean 38 vs 56 ms, p95 106 vs 130 ms, p99 213 vs 796 ms, max 1466 vs 6118 ms, and +47% throughput (1.03M vs 0.70M requests in the same window). ZGC's occasional allocation stalls cost far less than G1's multi-second stop-the-world pauses on this allocation-heavy, virtual-thread workload.
  • Memory: ZGC cgroup peak ~5.3G vs G1 ~1.3G. The gap is not GC overhead - with MALLOC_ARENA_MAX=2 the non-heap native is ~1.25G for both. It is ZGC eager-committing the 4G heap (file-backed) while G1 right-sized to ~370M for this small test live set; G1 could not be forced to hold 4G (-Xms4G/AlwaysPreTouch spiked then uncommitted). Under a production-sized live set the two converge.
  • Conclusion: with MALLOC_ARENA_MAX=2 the memory premium of ZGC shrinks to its eager heap commit (small in practice) while the latency/throughput win is clear. ZGC is therefore recommended for the virtual-thread worker pool (latency-sensitive deployments); G1 remains the safe default for tight or throughput-bound pods.

Why opt-in, not default

ZGC was initially made the default but reverted to opt-in before release. Defaulting it on would force a mandatory pod re-sizing onto every installation at upgrade time; an operator that did not re-size would silently hit the native-memory failure mode above (IMAP/SMTP connection failures, not an obvious OOM) - a poor default for large/cloud deployments. G1 has zero such sizing impact. The opt-in default is retained for conservatism (no forced re-sizing at upgrade time), but the latency/throughput benchmark has since been run (see "Load-test results" above) and favors ZGC: with MALLOC_ARENA_MAX=2 resolving most of the memory premium, ZGC is now the recommended collector for virtual-thread, latency-sensitive deployments, and a future release may reconsider it as the default.

Why ZGC, and why it fits the virtual-thread worker pool

The middleware request path now runs on a virtual-thread worker pool, which raises in-flight concurrency and the rate of short-lived, request-scoped allocations. G1's stop-the-world young/mixed collections scale with heap/live-set and pause all carrier threads at once, causing latency spikes across many virtual threads. Generational ZGC collects concurrently with sub-millisecond, heap-size-independent pauses, and its young generation suits exactly this short-lived-allocation pattern, giving stable tail latency under high concurrency. Compact Object Headers (also default) reduces live heap and further eases GC pressure. This synergy is why ZGC is offered as an opt-in for latency-sensitive, well-sized deployments.

Concerns / when to stay on G1

  • Native-memory headroom (see above) - largely mitigated by the MALLOC_ARENA_MAX=2 chart default, which brings ZGC's non-heap native down to G1 level and lets it fit a 6G limit; still budget the headroom and validate under load for mail/attachment-heavy workloads.
  • CPU: ZGC trades some throughput/CPU for low pauses. On CPU-starved pods its concurrent GC threads compete with the virtual-thread carriers and can raise latency. Ensure CPU headroom.
  • Allocation stalls: if the allocation rate outpaces concurrent collection (heap or CPU too small), ZGC stalls threads until memory is freed - the failure mode to watch under load spikes (monitor for "Allocation Stall" GC log lines).
  • Stay on G1 (the default) for very tight containers, throughput-/batch-bound workloads, or very small heaps where G1 is more CPU-efficient.
  • Virtual-thread pinning is orthogonal - ZGC does not pin virtual threads.
  • The latency/throughput benchmark has now been run (see "Load-test results" above) and favors ZGC; it used a small heap live set and under-exercised mail/attachment-heavy paths, so a heavier-mail load test is still advisable before flipping ZGC to the default in a future release.

About the virtual-thread worker pool

Virtual threads (JEP 444, stable since JDK 21) are lightweight JVM-managed threads multiplexed onto a small pool of OS "carrier" threads. A virtual thread blocked on I/O (IMAP/SMTP/DB) unmounts its carrier instead of holding an OS thread, so the server keeps far more requests in flight at roughly a stack's cost each rather than a full platform thread.

  • Benefit: HTTP throughput under high concurrency is no longer capped by a bounded worker pool, while blocking I/O stays simple (no async rewrite).
  • Behavioral changes: concurrency is no longer throttled by pool exhaustion - global back-pressure is now com.openexchange.threadpool.virtual.maxConcurrency (default auto); more in-flight requests mean higher peak heap/native use (hence the ZGC sizing above applies when ZGC is enabled); thread dumps show many short-lived virtual threads instead of a fixed named pool, and pool-saturation metrics no longer apply to HTTP work.
  • Fallback: com.openexchange.http.grizzly.virtualThreadsEnabled=false reverts to the platform-thread worker pool.
  • Virtual-thread pinning (a VT stuck to its carrier during synchronized/native sections) was audited - middleware code shows none; ZGC does not pin either.

Worker thread pool defaults (changed)

The shared worker thread pool ("OXWorker") previously shipped with an unbounded maximumPoolSize and a synchronous hand-off queue, allowing unbounded platform-thread creation under load. The Grizzly HTTP worker pool now runs on virtual threads by default (com.openexchange.http.grizzly.virtualThreadsEnabled=true) and is not governed by this pool; the bounded default guards non-HTTP work and the virtualThreadsEnabled=false fallback.

  • com.openexchange.threadpool.maximumPoolSize Maximum number of platform threads in the shared worker pool. Shipped default changed 2147483647 -> 2000. Not reloadable, not config-cascade aware. File: threadpool.properties.

  • com.openexchange.threadpool.workQueue Queue type for the shared worker pool. Shipped default changed synchronous -> linked. Combined with maximumPoolSize greater than corePoolSize this activates the ScalingQueue: threads scale up to maximumPoolSize, then excess tasks queue instead of spawning further threads. Not reloadable, not config-cascade aware. File: threadpool.properties.

  • com.openexchange.threadpool.virtual.maxConcurrency The maximum number of tasks that may run concurrently on the shared virtual-thread executor. Acts as a global back-pressure limit: once reached, submission of further tasks blocks until a running task completes. This is a process-wide overload limit, not a per-caller setting; individual fan-out sites may apply their own, narrower concurrency bound on top of it. Accepts a positive integer or the special value auto (default). With auto the limit is derived best-effort at start-up from the maximum heap size (the dominant constraint on in-flight request memory) and the active garbage collector: it scales with the heap and is reduced slightly under ZGC, which needs more native-memory headroom. The derived value is clamped to [512, 20000] and logged with its inputs at start-up (roughly ~4000 at a 4G heap on G1, ~3300 on ZGC). An explicit positive integer overrides the automatic value; a non-positive or unparseable value falls back to auto. Default auto (previously the fixed value 20000). Not reloadable, not config-cascade aware. File: threadpool.properties. Note: this is a memory-OOM safeguard, not a concurrency tuning target - the useful concurrency of blocking virtual-thread fan-out is almost always bound by a downstream pool (database connections, mail access, etc.) below this ceiling, which enforces its own narrower limit. The auto estimate is tunable via com.openexchange.threadpool.virtual.maxConcurrency.auto.heapFraction and com.openexchange.threadpool.virtual.maxConcurrency.auto.perRequestKB (below).

  • com.openexchange.threadpool.virtual.maxConcurrency.auto.heapFraction Fraction of the maximum heap budgeted for transient per-request state by the auto derivation of com.openexchange.threadpool.virtual.maxConcurrency; only consulted when that property is auto. Must be a decimal in (0, 1]; an absent, out-of-range or unparseable value falls back to 0.25. Not reloadable, not config-cascade aware. File: threadpool.properties.

  • com.openexchange.threadpool.virtual.maxConcurrency.auto.perRequestKB Estimated transient heap (in KiB) per in-flight request used by the auto derivation of com.openexchange.threadpool.virtual.maxConcurrency; only consulted when that property is auto. Raise it for requests with large transient state (buffered attachments, large responses) to make the safeguard more conservative; lower it for lightweight workloads. Must be a positive integer; an absent, non-positive or unparseable value falls back to 256. Not reloadable, not config-cascade aware. File: threadpool.properties.

8.51.88

3rd Party Libraries/License Change

SCR-1724

Summary: Upgraded OSGi core library

Effective: 8.51.88 and later; changed in 8.51.89

Upgraded OSGi core library in target platform (com.openexchange.bundles):

  • eclipse.osgi_3.24.0.v20251126-0427.jar upgraded to org.eclipse.osgi_3.24.200.v20260515-1403.jar

API - HTTP-API

SCR-1726

Summary: "sanitize_css" parameter for /mail?action=get

Effective: 8.51.88 and later; changed in 8.51.89

Adds an optional boolean query parameter sanitize_css to the /mail?action=get endpoint. It lets a client decide per request whether CSS content in HTML mail is sanitized against the white-list (in CleaningJsoupHandler and CssOnlyCleaningJsoupHandler), instead of always sanitizing.

If the parameter is absent or set to true, CSS content is sanitized against the white-list – unchanged behavior, so existing requests are unaffected. If set to false, CSS content is passed through unfiltered.

This affects CSS sanitizing only; HTML tag white-listing (the sanitize parameter) and external-image handling (the replace_external_images parameter) are independent. No configuration change and no API-breaking change.

API - REST

SCR-1714

Summary: New Administrative REST Servlet for Shared Accounts

Effective: 8.51.88 and later; changed in 8.51.89

Permissions and capabilities a particular user effectively has for a shared account are not persisted as such, but evaluated dynamically at runtime - based on the base configuration and all shared account permissions the user received, directly as well as indirectly through his group memberships. Since this calculated result can therefore not be deduced directly from the provisioned data, a dedicated administrative REST interface is available that answers the question: which effective permissions and capabilities does a certain user have for a shared account?

The endpoints are exposed below /preliminary/sharedaccounts/v1 and are protected via HTTP Basic Authentication, with the credentials configured through the properties com.openexchange.rest.services.basic-auth.login and com.openexchange.rest.services.basic-auth.password.

The user whose access is to be evaluated - and, where applicable, the targeted shared account - can be referenced in three alternative ways: by their explicit internal identifiers, by their email address, or by their mail login string.

See the general documentation, as well as the REST API documentation for further details.

Behavioral Changes

SCR-1717

Summary: Deny Write-Access for Guest Users in Public Calendar Folders

Effective: 8.51.88 and later; changed in 8.51.89

With MW-1473 write access for invited guest users was introduced. However, write access in a calendar folder also implies taking over the organizer role for scheduled appointments. This role cannot be hijacked for a foreign principal residing on an external calendaring and mail system a guest user originates from. Therefore, guest users may only receive write access for personal or shared calendar folders that are bound to a known internal calendar user they can act on behalf of, but not for public calendar folders.

See the documentation for further details.

Configuration

SCR-1583

Summary: Per-user Filters for LDAP Contacts Provider

Effective: 8.51.88 and later; changed in 8.51.89

Besides the distinguishing attribute placeholder [value] for the folders, the filter template in mode dynamicAttributes may now also contain several user- or session-specific placeholders which are replaced dynamically from the requesting user's session prior passing the query to LDAP. Doing so, it is possible to model different 'views' on the data, in case the user base is also represented through the LDAP directory, in combination with multi-value LDAP attributes.

See the documentation for the new replacement options and further details.

Database

SCR-1718

Summary: Update Task to Downscope Unsupported Guest Permissions

Effective: 8.51.88 and later; changed in 8.51.89

Update Task com.openexchange.groupware.update.tasks.DownscopeGuestPublicCalendarPermissionsTask

The blocking database update task 'com.openexchange.groupware.update.tasks.DownscopeGuestPublicCalendarPermissionsTask' is introduced to downscope write permissions of guest users on public calendar folders to "read-only".

With MW-1473 write access for invited guest users was introduced. However, write access in a calendar folder also implies taking over the organizer role for scheduled appointments. This role cannot be hijacked for a foreign principal residing on an external calendaring and mail system a guest user originates from. Therefore, guest users may only receive write access for personal or shared calendar folders that are bound to a known internal calendar user they can act on behalf of, but not for public calendar folders.

This task aligns already existing permissions accordingly by stripping object-write, object-delete, sub-folder/create-object as well as administrative folder permissions from any guest user permission on a public calendar folder, leaving folder- and object-read permissions untouched.

8.50.112

API - HTTP-API

SCR-1711

Summary: Added new cluster-internal REST endpoint to validate Middleware sessions for the JMAP-IMAP proxy

Effective: 8.50.112 and later

Motivation

The HTTP/REST API previously had no entry point that lets the cluster-internal JMAP-IMAP proxy resolve a user's Middleware session into the IMAP backend coordinates and credentials it needs to forward JMAP calls. Standalone JMAP clients can authenticate against the proxy directly via HTTP Basic / OIDC -- the App Suite UI cannot, because it only carries a Middleware session cookie.

This SCR closes that gap with a dedicated cluster-internal REST endpoint, hardened against credential exposure.

New Endpoint

  • Method + path: GET /preliminary/mail/v1/validate-session/<session>
  • Bundle: com.openexchange.mail.rest (new), registered via open-xchange-core.psf
  • Required path parameter: session -- the Middleware session identifier (length-capped to 128 chars)
  • Required header: X-OX-Session-Secret -- the plain value of the user's open-xchange-secret-<hash> cookie, forwarded by the proxy from the originating client request (length-capped to 512 chars)
  • HTTP Basic-Auth: gated by Role.BASIC_AUTHENTICATED (cluster-internal REST credentials com.openexchange.rest.services.basic-auth.*; identical to SessionRESTService)

The session is resolved in a touch-free manner via SessiondService.peekSession(String); repeated polling does not reset the session's idle expiration counter, so the proxy can poll at ~30 s without keeping otherwise idle sessions alive.

Response: AES-256-GCM Envelope

Because the response carries the user's plaintext mail password (LOGIN flow) / OAuth access token plus internal infrastructure details (IMAP host name, login, primary email), the entire success body is wrapped in an AES-256-GCM envelope.

Wire format on HTTP 200:

{
  "v": 1,
  "envelope": "v1:<base64-iv>:<base64-ct-with-tag>"
}

The ciphertext decodes to the inner payload:

{
  "identity": { "user", "context", "displayName", "primaryEmail" },
  "imap":     { "host", "port", "secure" },
  "auth":     { "type", "loginName", "secret", "secretExpiresInSeconds" },
  "session":  { "expiresInSeconds" }
}

auth.type ∈ `{LOGIN,XOAUTH2,OAUTHBEARER\}, mirroring the Middleware-internalAuthType` enum.

A fresh 12-byte random IV is generated per call. The caller's Basic-Auth identity (UTF-8 bytes) is additionally bound into the GCM authentication tag via Associated Authenticated Data, so an envelope captured from one caller cannot be successfully decrypted with a different caller's credentials. The proxy must pass the byte-identical AAD when decrypting; the wire format itself remains unchanged.

Error responses (401/403/429/503/500) are plaintext OX-error-JSON so the proxy can forward them to the originating client untouched.

Example request:

GET /preliminary/mail/v1/validate-session/abc123def456
Authorization: Basic <base64 of proxy credentials>
X-OX-Session-Secret: <secret cookie value>

Authentication

The endpoint enforces two independent authentication layers:

  • Authorization Basic-Auth gates the caller (proves "you're the JMAP-IMAP proxy"). Cluster-internal credentials, same pool as other internal REST endpoints.
  • X-OX-Session-Secret compared against session.getSecret() in constant time (via MessageDigest.isEqual) so the comparison's running time does not leak information about which bytes already matched. Prevents resolving arbitrary session identifiers -- the caller must have seen the user's actual cookies, otherwise the lookup fails.

After 5 consecutive secret-mismatch attempts on the same session identifier within a 10-minute window, the session itself is invalidated cluster-wide via SessiondService.removeSession(..., ADMIN_CLOSED). A legitimate proxy call never produces a mismatch, so the threshold cannot fire on real traffic.

Sessions whose OAuth access-token expiry (Session.PARAM_OAUTH_ACCESS_TOKEN_EXPIRY_DATE) is in the past are rejected upfront with SES-0203 rather than handed out as a dead token.

Error Handling

  • HTTP 401 (Basic-Auth missing/invalid) -- handled by the REST stack before the resource method runs.
  • HTTP 401 with OX error JSON (SES-0203 SESSION_EXPIRED) -- raised on unknown / expired sessions, missing / mismatching X-OX-Session-Secret, or expired OAuth tokens. The OXException chain matches SessionUtility.checkSecret byte-for-byte (OXEXCEPTION_PROPERTY_SESSION_EXPIRATION_REASON carries NO_SUCH_SESSION, NO_EXPECTED_SECRET_COOKIE or SECRET_MISMATCH), so the proxy can forward the resulting error JSON to the originating client untouched and the standard SES-0203 handling kicks in.
  • HTTP 403 with OX error JSON (MAIL-0114 MAIL_ACCESS_DISABLED) -- raised when the user has no primary mail account or the primary account is disabled.
  • HTTP 403 -- raised when TLS is required (com.openexchange.mail.rest.requireTls=true, default) and the request is not secure, or when the source IP is not contained in the configured allowlist (com.openexchange.mail.rest.allowedSourceIPs).
  • HTTP 429 (empty body) -- raised when a Basic-Auth identity exceeds 6 000 requests per minute. The proxy should treat this as a load signal and back off exponentially; do not forward to the originating client.
  • HTTP 503 with OX error JSON -- raised when the server-side AES-256 encryption key is missing or invalid. Fails closed: the endpoint never serves a plaintext fallback.

Operational Hardening

  • Cache-Control: no-store, no-cache, must-revalidate + Pragma: no-cache on every response so no HTTP intermediary along the in-cluster path persists the (encrypted) body.
  • Every call is audit-logged via AuditLogService with an outcome-specific event id (ox.mail.validateSession.success, ox.mail.validateSession.session-expired.<reason>, ox.mail.validateSession.mail-access-disabled, ox.mail.validateSession.error). Caller identity, session id and timestamp only; never the supplied secret value, never the user's password / token.

Configuration

The endpoint introduces a small set of properties, documented and tracked separately in SCR-1712:

  • com.openexchange.mail.rest.encryption.key (required) -- the AES-256 key shared with the JMAP-IMAP proxy
  • com.openexchange.mail.rest.requireTls (default true) -- toggle for TLS enforcement
  • com.openexchange.mail.rest.allowedSourceIPs (default empty) -- optional source-IP allowlist

The endpoint additionally reuses:

  • com.openexchange.rest.services.basic-auth.login / .password -- the cluster-internal REST credentials (shared with the other Role.BASIC_AUTHENTICATED endpoints)
  • com.openexchange.sessiond.sessionDefaultLifeTime / sessionLongLifeTime -- session lifetime estimation

SCR-1695

Summary: New Action 'hasActive' in Module 'mailfilter/v2'

Effective: 8.50.112 and later

In order to get a quick information if there are currently specific mail filter rules active or not for an account, the new action hasActive is introduced in module mailfilter/v2 of the HTTP API.

See the API documentation for further details.

SCR-1692

Summary: Additional Field 'com.openexchange.imap.rootFolderStatus' for Mail Account Root Folders

Effective: 8.50.112 and later

The folder model (FolderResponseData) of the HTTP API is extended by the additional read-only field com.openexchange.imap.rootFolderStatus (column id 3053). It is only available for the special, virtual mail account root folders (e.g. with if default0 or default14), if supported by the underyling IMAP server.

It contains information about the data within the mail account as JSON object - which currently is a simple overall containsUnread flag that is true whenever there is an unseen message within any of the contained mail folders.

See the documentation for further details.

Configuration

SCR-1696

Summary: New Configuration Property 'com.openexchange.mail.filter.options.vacation.minimumInterval.seconds'

Effective: 8.50.112 and later

A new property com.openexchange.mail.filter.options.vacation.minimumInterval.seconds has been introduced to allow configuring the minimum interval for seconds-based vacation Sieve rules.

When set to -1 (default), the use of seconds-based vacation rules is disabled. Any positive value defines the minimum number of seconds that must elapse between automated vacation responses sent to the same sender.

This property only takes effect if the IMAP server advertises the vacation-seconds capability.

See the [property documentation](https://documentation.open-xchange.com/components/middleware/config/8/#mode=search&term=com.openexchange.mail.filter.secondary.) for further details.

8.49.91

3rd Party Libraries/License Change

SCR-1689

Summary: Updated Netty libraries from v4.1.130 to v4.1.132

Effective: 8.49.91 and later

Updated Netty libraries from v4.1.130 to v4.1.131 in bundle io.netty

  • netty-buffer-4.1.132.Final.jar
  • netty-codec-4.1.132.Final.jar
  • netty-codec-dns-4.1.132.Final.jar
  • netty-codec-http2-4.1.132.Final.jar
  • netty-codec-http-4.1.132.Final.jar
  • netty-codec-socks-4.1.132.Final.jar
  • netty-common-4.1.132.Final.jar
  • netty-handler-4.1.132.Final.jar
  • netty-handler-proxy-4.1.132.Final.jar
  • netty-resolver-4.1.132.Final.jar
  • netty-resolver-dns-4.1.132.Final.jar
  • netty-transport-4.1.132.Final.jar
  • netty-transport-native-unix-common-4.1.132.Final.jar
  • netty-transport-classes-epoll-4.1.132.Final.jar
  • netty-transport-native-epoll-4.1.132.Final.jar
  • netty-transport-classes-kqueue-4.1.132.Final.jar
  • netty-transport-native-kqueue-4.1.132.Final.jar
  • netty-tcnative-classes-2.0.72.Final

API - Java

SCR-1681

Summary: Added DAVX5 constant to BuiltInProvider enum and deprecated SYNC_APP

Effective: 8.49.91 and later

Extended enum com.openexchange.client.onboarding.BuiltInProvider with a new constant DAVX5("davx5") for the DAVx5 Select onboarding provider. The existing SYNC_APP("syncapp") constant has been deprecated in favor of DAVX5.

API - REST

SCR-1680

Summary: Introduced new REST endpoint for DAVx5 Select configuration

Effective: 8.49.91 and later

A new REST endpoint is introduced to serve DAVx5 Select configuration JSON:

GET /davx5/v1/config/{token}

The endpoint supports two modes:

Initial setup (no Authorization header): Redeems a one-time token, creates an app-specific password scoped to CalDAV/CardDAV, and returns the full configuration including DAV URLs, credentials, and UI customization. The user identity is derived from the session reservation bound to the token.

Response:
{
  "baseRoot": "https://dav.example.org/dav/",
  "caldavRoot": "https://dav.example.org/caldav/",
  "carddavRoot": "https://dav.example.org/carddav/",
  "basicAuth": {
    "username": "peter@example.org",
    "password": "app-specific-password-here"
  },
  "customization": {
    "productName": "Example Mail",
    "description": "Sync service brought to you by Example Corp",
    "logoImage": "data:image/png;base64,iVBOR...",
    "headerImage": "https://example.com/header.png"
  },
  "supportInfos": {
    "linkDestination": "https://example.com/support",
    "linkTitle": "Contact Support",
    "description": "In case of any problem, please visit our support page."
  }
}

Authenticated re-query (Basic Auth header): Returns customization-only JSON with Cache-Control and ETag headers for efficient polling. The user identity is derived from the validated credentials. The token path segment is ignored in this mode.

Error responses: 401 (invalid credentials), 403 (token invalid/expired/used), 429 (rate limit exceeded), 500 (internal error), 503 (auth service unavailable).

Behavioral Changes

SCR-1682

Summary: Replaced Sync App with DAVx5 Select in Android onboarding scenarios

Effective: 8.49.91 and later

The former syncappinstall onboarding scenario for Android devices has been replaced by two new scenarios:

  • davx5install — A link to the DAVx5 Select app on the Google Play Store.
  • davx5setup — A one-time configuration link using the davx5://setup?config=<url> URI scheme that the DAVx5 Select app handles to automatically provision DAV URLs, an app-specific password, and optional UI customization.

The default values for the following properties have changed:

  • {}com.openexchange.client.onboarding.enabledScenarios: syncappinstall replaced by * davx5install, davx5setup

  • {}com.openexchange.client.onboarding.android.phone.scenarios: syncappinstall replaced by davx5install, davx5setup

  • {}com.openexchange.client.onboarding.android.tablet.scenarios: syncappinstall replaced by davx5install, davx5setup

A new davx5 capability is declared and awarded when both davx5install and davx5setup onboarding scenarios are enabled for a user.

CLT

SCR-1691

Summary: Added command-line tools for mail signatures

Effective: 8.49.91 and later

Added the following command-line tools for mail signatures

usage: listsignatures -c <contextId> -u <userId> -A <masterAdmin | contextAdmin> -P <masterAdminPassword |
                      contextAdminPassword> [-p <RMI-Port>] [-s <RMI-Server] [--responsetimeout <responseTimeout>] |
                      [-h]
 -A,--adminuser <adminUser>       Admin username
 -c,--context <contextId>         The context identifier
 -h,--help                        Prints this help text
 -p,--port <rmiPort>              The optional RMI port (default:1099)
 -P,--adminpass <adminPassword>   Admin password
    --responsetimeout <timeout>   The optional response timeout in seconds when reading data from server (default: 0s;
                                  infinite)
 -s,--server <rmiHost>            The optional RMI server (default: localhost)
 -u,--user <userId>               The user identifier


Command-line tool for listing signatures of a certain user.
usage: deletesignature -c <contextId> -u <userId> -s <signatureId> -A <masterAdmin | contextAdmin> -P
                       <masterAdminPassword | contextAdminPassword> [-p <RMI-Port>] [-s <RMI-Server] [--responsetimeout
                       <responseTimeout>] | [-h]
 -A,--adminuser <adminUser>       Admin username
 -c,--context <contextId>         The context identifier
 -h,--help                        Prints this help text
 -i,--identifier <signatureId>    The signature identifier
 -p,--port <rmiPort>              The optional RMI port (default:1099)
 -P,--adminpass <adminPassword>   Admin password
    --responsetimeout <timeout>   The optional response timeout in seconds when reading data from server (default: 0s;
                                  infinite)
 -s,--server <rmiHost>            The optional RMI server (default: localhost)
 -u,--user <userId>               The user identifier


Command line tool to delete a certain signatures of a user.

Configuration

SCR-1693

Summary: New Configuration Property 'com.openexchange.saml.validationClockSkew'

Effective: 8.49.91 and later

In order to configure a clock screw tolerance when validating assertions in SAML responses, the new lean configuration property com.openexchange.saml.validationClockSkew is introduced. It allows to configure a grace timespan in milliseconds which is considered when checking the NotOnOrAfter and NotBefore attributes for validity. It defaults to 0, and is neither reloadable, nor config-cascade-aware.

See the property documentation for further details.

SCR-1687

Summary: Renamed DAVx5 Select configuration properties

Effective: 8.49.91 and later

All DAVx5 Select configuration properties have been moved from the com.openexchange.davx5.\* prefix to com.openexchange.client.onboarding.davx5.\* as part of merging the com.openexchange.davx5.rest bundle into {}com.openexchange.client.onboarding.davx5. The three URL properties were additionally renamed for consistency with the existing onboarding naming convention. ||Old property||New property|| |com.openexchange.davx5.baseRoot|com.openexchange.client.onboarding.davx5.base.url| |com.openexchange.davx5.caldavRoot|com.openexchange.client.onboarding.davx5.caldav.url| |com.openexchange.davx5.carddavRoot|com.openexchange.client.onboarding.davx5.carddav.url| |com.openexchange.davx5.appPasswordType|com.openexchange.client.onboarding.davx5.appPasswordType| |com.openexchange.davx5.appPasswordName|com.openexchange.client.onboarding.davx5.appPasswordName| |com.openexchange.davx5.rateLimit.maxPerMinute|com.openexchange.client.onboarding.davx5.rateLimit.maxPerMinute| |com.openexchange.davx5.customization.productName|com.openexchange.client.onboarding.davx5.customization.productName| |com.openexchange.davx5.customization.description|com.openexchange.client.onboarding.davx5.customization.description| |com.openexchange.davx5.customization.logoImage|com.openexchange.client.onboarding.davx5.customization.logoImage| |com.openexchange.davx5.customization.headerImage|com.openexchange.client.onboarding.davx5.customization.headerImage| |com.openexchange.davx5.support.linkDestination|com.openexchange.client.onboarding.davx5.support.linkDestination| |com.openexchange.davx5.support.linkTitle|com.openexchange.client.onboarding.davx5.support.linkTitle| |com.openexchange.davx5.support.description|com.openexchange.client.onboarding.davx5.support.description|

The new URL properties ({}base.url, {}caldav.url, {}carddav.url) now fall back to the shared onboarding properties com.openexchange.client.onboarding.caldav.url and com.openexchange.client.onboarding.carddav.url when left empty, so deployments that already have CalDAV/CardDAV onboarding URLs configured may not need to set the DAVx5-specific URL properties at all.

SCR-1683

Summary: Added configuration properties for DAVx5 Select integration

Effective: 8.49.91 and later

Added the following new lean configuration properties:

DAV URL configuration (config-cascade aware):

  • com.openexchange.davx5.baseRoot DAV base URL. Default: empty.

  • com.openexchange.davx5.caldavRoot CalDAV root URL. Default: empty.

  • com.openexchange.davx5.carddavRoot CardDAV root URL. Default: empty.

App password settings (config-cascade aware):

  • com.openexchange.davx5.appPasswordType App password type. Must match an entry in app-password-apps.yml. Default: "calcarddav".

  • com.openexchange.davx5.appPasswordName Display name for the app password. Default: "DAVx5 Select".

UI customization (config-cascade aware):

  • com.openexchange.davx5.customization.productName Product name shown in DAVx5 Select. Default: "OX App Suite".

  • com.openexchange.davx5.customization.description Product description. Default: "Sync your calendars and contacts".

  • com.openexchange.davx5.customization.logoImage Logo image as data URI or HTTPS URL. Default: empty.

  • com.openexchange.davx5.customization.headerImage Header/banner image as data URI or HTTPS URL. Default: empty.

Support information (config-cascade aware):

  • com.openexchange.davx5.support.linkDestination Support link URL. Default: empty.

  • com.openexchange.davx5.support.linkTitle Support link title. Default: empty.

  • com.openexchange.davx5.support.description Support description. Default: empty.

Rate limiting (not config-cascade aware):

  • com.openexchange.davx5.rateLimit.maxPerMinute Maximum requests per IP per minute for the configuration endpoint. Set to 0 to disable. Default: 10. Onboarding (config-cascade aware):

  • com.openexchange.client.onboarding.davx5.tokenTimeoutSeconds Token timeout in seconds for the one-time configuration link. Default: 30.

Packaging/Bundles

SCR-1679

Summary: Removed Sync App onboarding bundle

Effective: 8.49.91 and later

Removed the former Sync App onboarding activator ({}SyncAppOnboardingActivator) and its configuration file client-onboarding-syncapp.properties from the com.openexchange.client.onboarding bundle.

The Sync App onboarding provider has been replaced by the DAVx5 Select onboarding provider

SCR-1678

Summary: Added new bundle com.openexchange.davx5.rest for DAVx5 Select integration

Effective: 8.49.91 and later

Added new bundle com.openexchange.davx5.rest to the open-xchange-dav package.

This bundle provides a JAX-RS REST endpoint for serving DAVx5 Select configuration JSON to Android devices during CalDAV/CardDAV onboarding.

8.48.66

3rd Party Libraries/License Change

SCR-1685

Summary: Updated & enhanced TwelveMonkeys ImageIO readers/writers

Effective: 8.48.66 and later

Updated & enhanced TwelveMonkeys ImageIO readers/writers

  • Updated common-image-3.8.3.jar to common-image-3.13.1.jar
  • Updated common-io--3.8.3.jar to common-io-3.13.1.jar
  • Updated common-lang-3.8.3.jar to common-lang-3.13.1.jar
  • Updated imageio-bmp-3.8.3.jar to imageio-bmp-3.13.1.jar
  • Updated imageio-clippath-3.8.3.jar to imageio-clippath-3.13.1.jar
  • Updated imageio-core-3.8.3.jar to imageio-core-3.13.1.jar
  • Added imageio-dds-3.13.1.jar
  • Updated imageio-hdr-3.8.3.jar to imageio-hdr-3.13.1.jar
  • Updated imageio-icns-3.8.3.jar to imageio-icns-3.13.1.jar
  • Updated imageio-iff-3.8.3.jar to imageio-iff-3.13.1.jar
  • Updated imageio-jpeg-3.8.3.jar to imageio-jpeg-3.13.1.jar
  • Updated imageio-metadata-3.8.3.jar to imageio-metadata-3.13.1.jar
  • Updated imageio-pcx-3.8.3.jar to imageio-pcx-3.13.1.jar
  • Updated imageio-pict-3.8.3.jar to imageio-pict-3.13.1.jar
  • Updated imageio-pnm-3.8.3.jar to imageio-pnm-3.13.1.jar
  • Updated imageio-psd-3.8.3.jar to imageio-psd-3.13.1.jar
  • Updated imageio-sgi-3.8.3.jar to imageio-sgi-3.13.1.jar
  • Updated imageio-tga-3.8.3.jar to imageio-tga-3.13.1.jar
  • Updated imageio-thumbsdb-3.8.3.jar to imageio-thumbsdb-3.13.1.jar
  • Updated imageio-tiff-3.8.3.jar to imageio-tiff-3.13.1.jar
  • Added imageio-webp-3.13.1.jar
  • Added imageio-xwd-3.13.1.jar

Configuration

SCR-1677

Summary: Added Helm chart support for PodDisruptionBudget

Effective: 8.48.66 and later

The core-mw Helm chart now supports the creation of a PodDisruptionBudget (PDB) per node type. A PDB limits the number of pods that can be voluntarily disrupted at any given time (e.g. during node drains or rolling updates), helping to maintain application availability.

The feature is disabled by default and can be enabled per type or globally via the pdb values section. Either pdb.minAvailable or pdb.maxUnavailable must be set when enabled.

Example configuration:

pdb:
  create: true
  minAvailable: 1

For more information, refer to the chart documentation.

SCR-1664

Summary: New Properties for Shared Accounts Configuration

Effective: 8.48.66 and later

For the new Shared Accounts feature, several lean configuration properties are introduced:

  • com.openexchange.sharedaccount.enabled
  • com.openexchange.sharedaccount.mail.defaultCapabilities
  • com.openexchange.sharedaccount.calendar.defaultCapabilities
  • com.openexchange.sharedaccount.mail.defaultPermissionSet
  • com.openexchange.sharedaccount.calendar.defaultPermissionSet
  • com.openexchange.sharedaccount.calendar.sentByPreference

See the property documentation, as well as the feature documentation for further details.

Database

SCR-1669

Summary: Update Tasks for Shared Account Tables

Effective: 8.48.66 and later

For the new Shared Accounts feature, new database tables sharedaccount_permissions and sharedaccount_usersettings are introduced through the blocking update tasks com.openexchange.sharedaccount.storage.rdb.groupware.SharedAccountStorageCreateTableTask.

The update- / create table task is located within package open-xchange-sharedaccount. See the feature documentation for further details.

SCR-1670

Summary: Update Task to add "type" column for Tables "user" and "del_user"

Effective: 8.48.66 and later

In order to differentiate between stored user records, the new column type is inserted for tables user and del_user through update task com.openexchange.groupware.update.tasks.UserAddTypeTask.

CLT

SCR-1668

Summary: New Commandline Utilities for Shared Accounts

Effective: 8.48.66 and later

To provision shared accounts and -permissions, new commandline utilities are introduced.

  • createsharedaccount
  • listsharedaccount
  • updatesharedaccount
  • deletesharedaccount
  • createsharedaccountpermissions
  • listsharedaccountpermissions
  • deletesharedaccountpermissions

See the feature documentation as well as the commandline tool reference for further details and synopsis.

API - SOAP

SCR-1667

Summary: New SOAP Service for Shared Accounts

Effective: 8.48.66 and later

To provision shared accounts and -permissions, the new SOAP API "http://soap.admin.openexchange.com/OXSharedAccountService" is introduced, offering methods:

  • change() - Changes shared account data within the given context.
  • create() - Creates a new shared account within the given context.
  • delete() - Deletes specified shared account(s) from given context.
  • list() - Retrieve all shared accounts for a given context.
  • listCaseInsensitive() - Retrieve all shared accounts for a given context.
  • getData() - Retrieve user objects for a range of shared accounts by username or id.
  • createSharedAccountPermissions() - Creates shared account permissions for a list of users and/or groups.
  • deleteSharedAccountPermissions() - Deletes specified shared account(s) from given context.
  • listSharedAccountPermissions() - Get all shared account permissions for the specified user.
  • listSharedAccountPermissionsForSharedAccount() - Get all shared account permissions for the specified shared account.

See the feature documentation for further details and example requests.

Packaging/Bundles

SCR-1666

Summary: New Package 'open-xchange-sharedaccount'

Effective: 8.48.66 and later

For the new Shared Accounts feature, the package open-xchange-sharedaccount is introduced.

See the feature documentation for further details.

API - HTTP-API

SCR-1665

Summary: New Module 'sharedaccount' in HTTP API

Effective: 8.48.66 and later

To access the available shared accounts of a user, the HTTP API is extended by new module sharedaccount.

See the API documentation for further details, including all new endpoints.

SCR-1671

Summary: New Parameter 'sentBy' in Actions of Module 'chronos/itip' Module of HTTP API

Effective: 8.48.66 and later

All modifying actions of module chronos/itip are extended by a new, optional parameter sentBy.

This can be used to explicitly specify the calendar user that is acting on behalf of the calendar user for the scope of the current calendar operation. If set, it'll be picked up as originator for generated notification and scheduling mails (through MIME header Sender), and for the SENT-BY parameter in ORGANIZER or ATTENDEE properties within generated iTIP data.

If not set, the on behalf relationship is implicitly determined based on the actual folder view.

The value can either be supplied using the numerical user identifier, or by the calendar user address URI.

See the [API documentation)[https://documentation.open-xchange.com/components/middleware/http/8/index.html#!Chronos] for further details.

8.47.52

General

SCR-1656

Summary: Updated Apache Commons CLI library from v1.9.0 to v1.11.0

Effective: 8.47.52 and later

Updated Apache Commons CLI library from v1.9.0 to v1.11.0 in target platform (com.openexchange.bundles)

SCR-1650

Summary: Updated Jackson libraries from v2.19.2 to v2.21.0 in target platform

Effective: 8.47.52 and later

Updated Jackson libraries from v2.19.2 to v2.21.0 in `}com.openexchange.bundles}

  • jackson-annotations v2.19.2 to v2.21.0
  • jackson-core v2.19.2 to v2.21.0
  • jackson-databind v2.19.2 to v2.21.0
  • jackson-dataformat-cbor v2.19.2 to v2.21.0
  • jackson-dataformat-xml v2.19.2 to v2.21.0
  • jackson-dataformat-yaml v2.19.2 to v2.21.0
  • jackson-datatype-jsr310 v2.19.2 to v2.21.0
  • jackson-datatype-jsr353 v2.19.2 to v2.21.0
  • jackson-jakarta-rs-base v2.19.2 to v2.21.0
  • jackson-jakarta-rs-json-provider v2.19.2 to v2.21.0
  • jackson-jakarta-rs-xml-provider v2.19.2 to v2.21.0
  • jackson-module-jakarta-xmlbind-annotations v2.19.2 to v2.21.0
  • jackson-module-jaxb-annotations v2.19.2 to v2.21.0

3rd Party Libraries/License Change

SCR-1657

Summary: Updated Apache Commons Collections4 library from v4.4 to v4.5.0

Effective: 8.47.52 and later

Updated Apache Commons Collections4 library from v4.4 to v4.5.0 in target platform (com.openexchange.bundles)

SCR-1655

Summary: Update Apache Commons Codec

Effective: 8.47.52 and later

Updated Apache Commons Codec from v.1.17.2 to v1.21.0 in target platform (com.openexchange.bundles)

SCR-1654

Summary: Updated Apache Mime4j

Effective: 8.47.52 and later

Updated Apache Mime4j libraries in target platform (com.openexchange.bundles)

  • apache-mime4j-core-0.8.10.jar -> apache-mime4j-core-0.8.13.jar
  • apache-mime4j-dom-0.8.10jar -> apache-mime4j-dom-0.8.13.jar
  • apache-mime4j-storage-0.8.10.jar -> apache-mime4j-storage-0.8.13.jar

SCR-1653

Summary: Upgraded JSoup library

Effective: 8.47.52 and later

Upgraded JSoup library from v1.21.1 to v1.22.1 in target platform (com.openexchange.bundles)

SCR-1652

Summary: Updated OSGi target platform bundles

Effective: 8.47.52 and later

Updated the following OSGi target platform bundles

  • org.eclipse.osgi_3.23.200.v20250812-1847.jar updated to org.eclipse.osgi_3.24.0.v20251126-0427.jar

SCR-1649

Summary: Updated Fabric8 libraries from v7.4.0 to v7.5.2

Effective: 8.47.52 and later

Updated Fabric8 ibraries from v7.4.0 to v7.5.2 in bundle io.fabric8.kubernetes

  • kubernetes-client-7.5.2.jar
  • kubernetes-client-api-7.5.2.jar
  • kubernetes-httpclient-jdk-7.5.2.jar
  • kubernetes-model-admissionregistration-7.5.2.jar
  • kubernetes-model-apiextensions-7.5.2.jar
  • kubernetes-model-apps-7.5.2.jar
  • kubernetes-model-autoscaling-7.5.2.jar
  • kubernetes-model-batch-7.5.2.jar
  • kubernetes-model-certificates-7.5.2.jar
  • kubernetes-model-common-7.5.2.jar
  • kubernetes-model-coordination-7.5.2.jar
  • kubernetes-model-core-7.5.2.jar
  • kubernetes-model-discovery-7.5.2.jar
  • kubernetes-model-events-7.5.2.jar
  • kubernetes-model-extensions-7.5.2.jar
  • kubernetes-model-flowcontrol-7.5.2.jar
  • kubernetes-model-gatewayapi-7.5.2.jar
  • kubernetes-model-metrics-7.5.2.jar
  • kubernetes-model-networking-7.5.2.jar
  • kubernetes-model-node-7.5.2.jar
  • kubernetes-model-policy-7.5.2.jar
  • kubernetes-model-rbac-7.5.2.jar
  • kubernetes-model-resource-7.5.2.jar
  • kubernetes-model-scheduling-7.5.2.jar
  • kubernetes-model-storageclass-7.5.2.jar
  • zjsonpatch-7.5.2.jar

SCR-1648

Summary: Updated lettuce library from v6.5.5 to v6.8.2

Effective: 8.47.52 and later

Updated lettuce library from v6.5.5 to v6.8.2 in bundle io.lettuce

  • lettuce-core-6.8.2.RELEASE.jar

SCR-1647

Summary: Updated Netty libraries

Effective: 8.47.52 and later

Updated Netty libraries from v4.1.124 to v4.1.130 in bundle io.netty

  • netty-buffer-4.1.130.Final.jar
  • netty-codec-4.1.130.Final.jar
  • netty-codec-dns-4.1.130.Final.jar
  • netty-codec-http2-4.1.130.Final.jar
  • netty-codec-http-4.1.130.Final.jar
  • netty-codec-socks-4.1.130.Final.jar
  • netty-common-4.1.130.Final.jar
  • netty-handler-4.1.130.Final.jar
  • netty-handler-proxy-4.1.130.Final.jar
  • netty-resolver-4.1.130.Final.jar
  • netty-resolver-dns-4.1.130.Final.jar
  • netty-transport-4.1.130.Final.jar
  • netty-transport-native-unix-common-4.1.130.Final.jar
  • netty-transport-classes-epoll-4.1.130.Final.jar
  • netty-transport-native-epoll-4.1.130.Final.jar
  • netty-transport-classes-kqueue-4.1.130.Final.jar
  • netty-transport-native-kqueue-4.1.130.Final.jar
  • netty-tcnative-classes-2.0.72.Final

SCR-1646

Summary: Updated OpenId Connect libraries

Effective: 8.47.52 and later

Updated OpenId Connect libraries in bundle com.nimbus:

  • accessors-smart-2.4.11.jar updated to accessors-smart-2.5.2.jar
  • asm-9.1.jar updated to asm-9.7.1.jar
  • content-type-2.2.jar updated to content-type-2.3.jar
  • json-smart-2.4.11.jar updated to json-smart-2.5.2.jar
  • nimbus-jose-jwt-10.0.2.jar updated to nimbus-jose-jwt-10.6.jar
  • oauth2-oidc-sdk-10.7.jar updated to oauth2-oidc-sdk-11.32.jar

SCR-1641

Summary: Added RE2/J - linear time regular expression matching in Java

Effective: 8.47.52 and later

Added Google Open Source library RE2/J "re2j-1.8.jar" as bundle to target platform "com.openexchange.bundles". RE2 is a regular expression engine that runs in time linear in the size of the input.

SCR-1638

Summary: Updated Spring Framework libraries

Effective: 8.47.52 and later

Updated Spring Framework libraries from v5.3.39 to v6.2.15 in bundle com.openexchange.xml

  • com.openexchange.xml/lib/spring-beans-5.3.39.jar -> com.openexchange.xml/lib/spring-beans-6.2.15.jar
  • com.openexchange.xml/lib/spring-core-5.3.39.jar -> com.openexchange.xml/lib/spring-core-6.2.15.jar
  • com.openexchange.xml/lib/spring-jcl-5.3.39.jar -> com.openexchange.xml/lib/spring-jcl-6.2.15.jar

API - Java

SCR-1505

Summary: Added methods to the MultifactorLoginService

Effective: 8.47.52 and later

Extended the com.openexchange.login.multifactor.MultifactorLoginService interface by following methods:

    /**

     * Checks if multi-factor enforcement property is set and the enforceMfa flag is set for a given user.
     *
     * @param userId The user identifier
     * @param contextId The context identifier
     * @return <code>true<code> If multi-factor enforcement is enabled
     * @throws OXException
     */
    boolean checkEnforceMultiFactorAuthentication(int userId, int contextId)throws OXException;

    /**

     * Checks if multi-factor enforcement property is set for a given user.
     *
     * @param userId The user identifier
     * @param contextId The context identifier
     * @return <code>true<code> If multi-factor enforcement is enabled as dismissable; otherwise <code>false</code>
     * @throws OXException If something went wrong trying to access the database
     */
    boolean checkEnforceMultiFactorAuthenticationDismissable(int userId, int contextId);

    /**

     * Records the login attempt for a given user.
     *
     * @param userId The user identifier
     * @param contextId The context identifier
     * @throws OXException If something went wrong trying to access the database
     */
    void recordLoginAttempt(int id, int contextId) throws OXException;

    /**

     * Gets the login information record.
     *
     * @param userId The user identifier
     * @param contextId The context identifier
     * @return A MultifactorEnforcementInformation record holding the information
     * @throws OXException If something went wrong trying to access the database
     */
    MultifactorEnforcementInformation getLoginInformation(int id, int contextId) throws OXException;

    /**

     * Enhances JSON with multi-factor enforcement data.
     *
     * @param json The JSON content to enhance
     * @param userId The user identifier
     * @param contextId The context identifier
     */
    void enhanceLoginJson(JSONObject json, int userId, int contextId);

    /**

     * Resets the login information for an user.
     *
     * @param userId The user identifier
     * @param contextId The context identifier
     * @throws OXException If something went wrong trying to access the database
     */
    void resetLoginInformation(int userId, int contextId) throws OXException;

API - REST

SCR-1504

Summary: Introduced a new REST interface for multifactor enforcement

Effective: 8.47.52 and later

New REST endpoint is introduced in order to manage multifactor enforcement.

Retrieve login information for a certain user:

GET /admin/v1/contexts/\{context-id}/users/\{user-id}/multifactor/enforcement

Response:
{
  "enforceMfa": true,
  "loginCounter": 5,
  "firstLogin": "<time-stamp>"
}

Reset login information for a certain user:

DELETE /admin/v1/contexts/\{context-id}/users/\{user-id}/multifactor/enforcement

CLT

SCR-1503

Summary: Add CLT for multifactor enforcement

Effective: 8.47.52 and later

Command-line tool resetenforcemfa to allow a reset of the multi-factor enforcement informations

usage: resetenforcemfa -c <contextId> -i <userId> -A <masterAdmin | contextAdmin> -P <masterAdminPassword |
                       contextAdminPassword>
 -A,--adminuser <adminuser>       Admin username
    --api-host <arg>              URL for an alternative REST end-point host. Example: 'https://192.168.0.1:8443'.
                                  Default: 'http://localhost:8009'
    --api-root <arg>              URL to an alternative HTTP API endpoint. Example: 'https://192.168.0.1:8443/admin/v1/'
 -c,--contextid <arg>             A valid context identifier.
 -h,--help                        Prints this help text
 -i,--userid <arg>                A valid user identifier.
 -P,--adminpass <adminpassword>   Admin password


The command-line tool to reset the multifactor enforcement for an user.

Configuration

SCR-1645

Summary: Added various properties for proxy functionality

Effective: 8.47.52 and later

Added various lean properties for proxy functionality

  • com.openexchange.proxy.path Specifies the path taken when replacing URIs and for registering proxy Servlet. Default value is "/servlet/proxy". It is reloadable, but not config-cascade aware.

  • com.openexchange.proxy.servlet.enabled The switch to enable/disable Proxy Servlet. Default value is true. It is reloadable, but not config-cascade aware. If Proxy Servlet is enabled, com.openexchange.proxy.encoding is required being set to "object".

  • com.openexchange.proxy.encoding The method how original URI and accompanying proxy registration is encoded. "plain": Only the original URI is base64-encoded. "object": The complete registration object is compressed and obfuscated within a base64 representation. Default value is "object". It is reloadable, but not config-cascade aware.

SCR-1501

Summary: Added new properties for MFA enforcement

Effective: 8.47.52 and later

Introduced new lean webauthn properties to use webauthn as a 2nd factor and as a preparation for webautn as a "full" authentication service * com.openexchange.multifactor.enabled Defines if MFA should be enforced.

  • com.openexchange.multifactor.login_limit Configures the amount of login attempts a user can do before MFA is really enforced.

  • com.openexchange.multifactor.period_limit Configures the period of time in days, starting from the first login, which defines when MFA is really enforced.

Database

SCR-1502

Summary: Add table for mfa enforcement

Effective: 8.47.52 and later

Update Task com.openexchange.multifactor.enforcement.storage.rdb.CreateMultifactorEnforcementTableTask

In order to implement the possibility to enforce multi-factor, a database table called multifactor_enforcement needs to be created to store the relevant informations.

CREATE TABLE `multifactor_enforcement`(
  `cid` int(10) unsigned NOT NULL,
  `id` int(10) unsigned NOT NULL,
  `enforceMfa` TINYINT(1) DEFAULT 0,
  `loginCounter` int(10) DEFAULT 0,
  `firstLogin` DATETIME DEFAULT NULL,
  PRIMARY KEY (`cid`, `id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"

8.46.83

3rd Party Libraries/License Change

SCR-1637

Summary: Upgraded Apache Tika and Commons IO libraries

Effective: 8.46.83 and later

Updated Apache Tika library from v2.8.0 to v3.2.3 in bundle com.openexchange.tika.util, also updated Apache Commons IO library from v2.18.0 to v2.21.0 in bundle com.openexchange.bundles.

Behavioral Changes

SCR-1635

Summary: Changed Handling of TEL Preference in vCard Mapping

Effective: 8.46.83 and later

Up to now, the pref attribute has been used to indicate the first telephone number of the contact when writing to or reading from vCards, whenever an OX contact property has more than one telephone number of a certain type. In particular, this was considered for telephone_business1 / telephone_business2, telephone_home1 / telephone_home2 and cellular_telephone1 / cellular_telephone2.

For some clients, this handling led to ambiguities where an overall pref attribute is used to mark the preferred telephone number across all types.

Therefore, to not interfere with a client-defined preference, the mapping routine is adjusted so that the custom attribute x-1st will be used to differentiate between multiple candidates. See the documentation for further details.

8.45.48

General

SCR-1625

Summary: Updated Caffeine caching library and Google Guava

  • Updated Caffeine caching library from v3.2.0 to v3.2.3 in bundle com.google.guava
  • Updated Google Guava from v33.3.0 to v33.5.0 in bundle com.google.guava

3rd Party Libraries/License Change

SCR-1628

Summary: Updated several libraries

Updated several libraries in target platform and bundles

Target platform libraries (com.openexchange.bundles)

  • jackson-annotations v2.19.0 to v2.19.2
  • jackson-core v2.19.0 to v2.19.2
  • jackson-databind v2.19.0 to v2.19.2
  • jackson-dataformat-cbor v2.19.0 to v2.19.2
  • jackson-dataformat-xml v2.19.0 to v2.19.2
  • jackson-dataformat-yaml v2.19.0 to v2.19.2
  • jackson-datatype-jsr310 v2.19.0 to v2.19.2
  • jackson-datatype-jsr353 v2.19.0 to v2.19.2
  • jackson-jakarta-rs-base v2.19.0 to v2.19.2
  • jackson-jakarta-rs-json-provider v2.19.0 to v2.19.2
  • jackson-jakarta-rs-xml-provider v2.19.0 to v2.19.2
  • jackson-module-jakarta-xmlbind-annotations v2.19.0 to v2.19.2
  • jackson-module-jaxb-annotations v2.19.0 to v2.19.2

  • jcl-over-slf4j v2.0.16 to v2.0.17

  • jul-to-slf4j v2.0.16 to v2.0.17

  • log4j-over-slf4j v2.0.16 to v2.0.17

  • logback-classic v1.5.16 to v1.5.21

  • logback-core v1.5.16 to v1.5.21

  • osgi-over-slf4j v2.0.16 to v2.0.17

  • slf4j-api v2.0.16 to v2.0.17

Inlined libraries

com.ctc.wstx

  • woodstox-core v7.1.0 to v7.1.1

io.fabric8.kubernetes

  • kubernetes-client v6.13.4 to v7.4.0
  • kubernetes-client-api v6.13.4 to v7.4.0
  • kubernetes-httpclient-jdk v6.13.4 to v7.4.0
  • kubernetes-model-admissionregistration v6.13.4 to v7.4.0
  • kubernetes-model-apiextensions v6.13.4 to v7.4.0
  • kubernetes-model-apps v6.13.4 to v7.4.0
  • kubernetes-model-autoscaling v6.13.4 to v7.4.0
  • kubernetes-model-batch v6.13.4 to v7.4.0
  • kubernetes-model-certificates v6.13.4 to v7.4.0
  • kubernetes-model-common v6.13.4 to v7.4.0
  • kubernetes-model-coordination v6.13.4 to v7.4.0
  • kubernetes-model-core v6.13.4 to v7.4.0
  • kubernetes-model-discovery v6.13.4 to v7.4.0
  • kubernetes-model-events v6.13.4 to v7.4.0
  • kubernetes-model-extensions v6.13.4 to v7.4.0
  • kubernetes-model-flowcontrol v6.13.4 to v7.4.0
  • kubernetes-model-gatewayapi v6.13.4 to v7.4.0
  • kubernetes-model-metrics v6.13.4 to v7.4.0
  • kubernetes-model-networking v6.13.4 to v7.4.0
  • kubernetes-model-node v6.13.4 to v7.4.0
  • kubernetes-model-policy v6.13.4 to v7.4.0
  • kubernetes-model-rbac v6.13.4 to v7.4.0
  • kubernetes-model-resource v6.13.4 to v7.4.0
  • kubernetes-model-scheduling v6.13.4 to v7.4.0
  • kubernetes-model-storageclass v6.13.4 to v7.4.0
  • snakeyaml-engine v2.7 to v2.10
  • jsonpatch v0.3.0 to v7.4.0

SCR-1626

Summary: Added Eclipse Collections to target platform

Added Eclipse Collections to target platform (com.openexchange.bundles):

  • eclipse-collections-api-13.0.0.jar
  • eclipse-collections-13.0.0.jar

Eclipse Collections is a collections framework for Java with optimized data structures and a rich, functional and fluent API.

Behavioral Changes

SCR-1634

Summary: Changed Semantics for 'com.openexchange.carddav.addressbookMultigetLimit' and 'com.openexchange.caldav.calendarMultigetLimit'

For increased client compatibility, the semantics of the configuration properties com.openexchange.carddav.addressbookMultigetLimit and com.openexchange.caldav.calendarMultigetLimit are changed in way that the configured value now determines up to which number of elements a synchronous processing of the response is performed. If data from more elements was requested, the data will be outputted to the HTTP response chunk-wise, instead of filling up with HTTP/1.1 507 Insufficient Storage responses as before.

See the property documentation for further details.

Configuration

SCR-1627

Summary: Added possibility to specify max. days in future as limitation for the date to send of a scheduled mail

Added property com.openexchange.mail.scheduled.maxDaysInFuture to specify max. days in future as limitation for the date to send of a scheduled mail. That property specifies the max. number of days in future that is allowed for the date to send. A value of 0 (zero) or a negative value disables this limitation. Default value is 0. It is reloadable and config-cascade aware.

8.44.28

General

SCR-1613

Summary: Added new property specifying that server-associated capabilities should be cached on a per user basis

Added new lean property com.openexchange.imap.cache.serverCapabilitiesPerUser specifying that server-associated capabilities should be cached on a per user basis. This is useful for setups with some sort of IMAP proxy in front forwarding to heterogeneous IMAP back-ends. Default is false. It is reloadable as well as config-cascade aware.

API - SOAP

SCR-1619

Summary: New Element 'primaryAddress' in 'accountDataUpdate' for 'OXSecondaryAccountService'

In order to set a new primary email address for a secondary account, the accountDataUpdate element within the update SOAP body of OXSecondaryAccountService service port is extended with a new optional element primaryAddress.

While changing the address, the targeted account still needs to be supplied via parent element primaryAddress, afterwards, the secondary mail account is acceesible using the new primary address.

Example:

<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:update>
         <soap:primaryAddress>service@context1.ox.test</soap:primaryAddress>
         <soap:accountDataUpdate>
            <xsd:primaryAddress>service2@context1.ox.test</xsd:primaryAddress>
            <xsd:name>service2@context1.ox.test</xsd:name>
            <xsd:personal>Service 2 &lt;service2@context1.ox.test</xsd:personal>
            <xsd:login>service2@context1.ox.test</xsd:login>
         </soap:accountDataUpdate>
         [...]
      </soap:update>
   </soapenv:Body>
</soapenv:Envelope>

CLT

SCR-1620

Summary: New Option '--new-primary-address' for 'updatesecondaryaccount'

In order to set a new primary email address for a secondary account, the commandline utility updatesecondaryaccount is extended with a new optional argument --new-primary-address.

While changing the address, the targeted account still needs to be supplied via mandatory parameter primary-address, afterwards, the secondary mail account is accessible using the new primary address.

See the documentation for further details.

Configuration

SCR-1623

Summary: Added new property to specify preferred snippet service to use

Added new lean property "com.openexchange.snippet.preferredSnippetService" to specify preferred snippet service to use. Default value is empty (no preferred snippet service). It is reloadable and config-cascade aware.

Accepted values are:

  • "database" for database-backed snippet service
  • "filestore" for filestore-backed snippet service

SCR-1622

Summary: Added new property for read duration threshold

Added new lean property com.openexchange.mail.bodyPartReadThresholdMillis that specifies the threshold in milliseconds for the read duration of body parts from mail storage. If that threshold is exceeded a warn log message is generated. Default value is 3000 (3 seconds). It is reloadable, but not config-cascade aware. A value of less than/equal to 0 (zero) disables this threshold.

SCR-1621

Summary: New Property 'com.openexchange.calendar.allowChangeOfOrganizerWithExternals'

Changing the organizer in group-scheduled events is an out-of-band process that might not be compatible with iTIP clients. In order to allow changing the organizer for mettings with only context-internal participants, there's property com.openexchange.calendar.allowChangeOfOrganizer already available, which enables clients changing the organizer via HTTP API - however this only works if the new organizer and all attendees of the event are context-internal users.

Now to also allow this for events with external attendees, the new lean configuration property {}com.openexchange.calendar.allowChangeOfOrganizerWithExternals. It is reloadable and can be defined through the config-cascade. See the property documentation for further details.

SCR-1618

Summary: New Properties to Enable Custom Login Source for Drive Client Onboarding

In order to enable usage of a registered custom login source when preparing details for the driveappmanual and drivewindowsclientmanual onboarding scenarios, the following new lean configuration properties are introduced:

  • com.openexchange.client.onboarding.drivewindowsclient.login.customsource
  • com.openexchange.client.onboarding.driveapp.login.customsource

Both default to false, are reloadable and can be defined through the config cascade.

SCR-1617

Summary: New Scenarios for Manual Drive Client Onboarding Configuration

The available onboarding scenarios are extended with two new "manual" configuration options for the Drive App, with the following identifiers:

  • driveappmanual
  • drivewindowsclientmanual

Accompanying the corresponding link / installer scenarios, these new options can be enabled and configured within the scenario configuration file {}client-onboarding-scenarios.yml, and added to the respective enabled scenarios per platform in configuration file {}client-onboarding.properties.

See template file client-onboarding-scnearios-template.yml for further details.

8.43.52

3rd Party Libraries/License Change

SCR-1612

Summary: Updated Spring Framework libraries

Updated Spring Framework libraries from v5.3.32 to v5.3.39 in bundle com.openexchange.xml

  • com.openexchange.xml/lib/spring-beans-5.3.32.jar -> com.openexchange.xml/lib/spring-beans-5.3.39.jar
  • com.openexchange.xml/lib/spring-core-5.3.32.jar -> com.openexchange.xml/lib/spring-core-5.3.39.jar
  • com.openexchange.xml/lib/spring-jcl-5.3.32.jar -> com.openexchange.xml/lib/spring-jcl-5.3.39.jar

SCR-1604

Summary: Updated OSGi target platform bundles

Updated the following OSGi target platform bundles

  • org.eclipse.osgi_3.23.100.v20250514-1759.jar updated to org.eclipse.osgi_3.23.200.v20250812-1847.jar

Behavioral Changes

SCR-1610

Summary: Implicitly Delete Alarms when Declining a Task

Previously, when a participant in a task changed his conformation status to "declined", any previously stored personal reminders of this user for that task were persisted, but no longer exposed via API when requested in the range action.

Now, any previously stored personal reminders are purged directly when changing the user's confirmation status to "declined".

Configuration

SCR-1611

Summary: Added new option to enable round-robin on IP address selection

Added new lean property "com.openexchange.imap.useMultipleAddressesRoundRobin" to enable round-robin on IP address selection. Default is false. Reloadable and config-cascade aware.

Requires "com.openexchange.imap.useMultipleAddresses" to be set to true

SCR-1609

Summary: New Configuration Property 'com.openexchange.reminder.maxRemindersPerRequest'

To define the maximum number of reminders for tasks that are processed and returned to the client during the range action, the new the new lean configuration property com.openexchange.reminder.maxRemindersPerRequest is introduced. By default (value of {}-1), it remains unrestricted to not change semantics.

The property is reloadable and can be defined through the config-cascade. See the property documentation for further details.

SCR-1608

Summary: New Configuration Property 'com.openexchange.reminder.reminderLookbackDays'

In order to configure the maximum number of days how far reminders for tasks are fetched within the range action, the new lean configuration property com.openexchange.reminder.reminderLookbackDays is introduced. By default (value of -1), it remains unrestricted to not change semantics.

The property is reloadable and can be defined through the config-cascade. See the property documentation for further details.

SCR-1607

Summary: New property 'com.openexchange.calendar.lookupPeerAttendeesEnabled'

By default, the server tries to lookup data from the same event of other attendee copies automatically, so that a changed participation status becomes directly visible for other users without waiting for an updated iTIP message of the organizer. In order to disable this implicit peer attendee lookup, the new lean configuration property com.openexchange.calendar.lookupPeerAttendeesEnabled is introduced. It defaults to true, is reloadable, and can be configured through the config-cascade.

See also the documentation for further details.

SCR-1606

Summary: New property 'com.openexchange.caldav.calendarMultigetLimit'

The new lean configuration property com.openexchange.caldav.calendarMultigetLimit is introduced which allows to configure the maximum number of elements included in CAL:calendar-multiget responses to the client. If data from more elements was requested, HTTP/1.1 507 Insufficient Storage responses will get inserted.

A value of -1 disables the limit. It defaults to 1000, is reloadable and can be defined through the config-cascade.

SCR-1605

Summary: New property 'com.openexchange.calendar.maxAttendeesPerConflictCheck'

In order to prevent exhausting conflict checks while creating events with a huge number of attendees, the new lean configuration property com.openexchange.calendar.maxAttendeesPerConflictCheck is introduced. It defaults to 50, is reloadable and can be defined through the config-cascade.

SCR-1603

Summary: New Configurartion Properties for 'movecontextdatabase'

To tweak the behavior of the movecontextdatabase utility, especially when dealing with large amounts of data being transferred, the following lean configuration properties are introduced:

  • com.openexchange.admin.context.move.intermediateCommits = false: Controls whether to perform intermediate database COMMITs after each batch during the context move operation.
  • com.openexchange.admin.context.move.selectBatchSize = 250000: The maximum number of rows to select per batch from the source database tables. A value of -1 disables processing in batches while reading.
  • com.openexchange.admin.context.move.insertBatchSize = 50000: The maximum number of rows to insert per batch into the destination database tables. A value of -1 disables processing in batches while writing.
  • com.openexchange.admin.context.move.deleteBatchSize = 50000: The maximum number of rows to delete per batch from the source database tables after the data was copied, or when undoing the operation. A value of -1 disables processing in batches while deleting.

All properties are reloadable, and can be defined through the config-cascade up to context scope. See also the property documentation for further details.

SCR-1599

Summary: Rename Property "com.openexchange.mail.proxyExternalImagerUrls"

To avoid confusions, the name of the lean property com.openexchange.mail.proxyExternalImagerUrls is adjusted to com.openexchange.mail.proxyExternalImageUrls.

See the property documentation for further details.

8.42.48

3rd Party Libraries/License Change

SCR-1598

Summary: Updated UnboundID LDAP SDK from v5.1.4 to v7.0.3

Updated UnboundID LDAP SDK from v5.1.4 to v7.0.3 in bundle com.openexchange.ldap.common

SCR-1597

Summary: Updated Netty libraries from v4.1.121 to v4.1.124 in bundle io.netty

Updated Netty libraries from v4.1.121 to v4.1.124 in bundle io.netty

  • netty-buffer-4.1.124.Final.jar
  • netty-codec-4.1.124.Final.jar
  • netty-codec-dns-4.1.124.Final.jar
  • netty-codec-http2-4.1.124.Final.jar
  • netty-codec-http-4.1.124.Final.jar
  • netty-codec-socks-4.1.124.Final.jar
  • netty-common-4.1.124.Final.jar
  • netty-handler-4.1.124.Final.jar
  • netty-handler-proxy-4.1.124.Final.jar
  • netty-resolver-4.1.124.Final.jar
  • netty-resolver-dns-4.1.124.Final.jar
  • netty-transport-4.1.124.Final.jar
  • netty-transport-native-unix-common-4.1.124.Final.jar
  • netty-transport-classes-epoll-4.1.124.Final.jar
  • netty-transport-native-epoll-4.1.124.Final.jar
  • netty-transport-classes-kqueue-4.1.124.Final.jar
  • netty-transport-native-kqueue-4.1.124.Final.jar
  • netty-tcnative-classes-2.0.72.Final

SCR-1596

Summary: Updated Bouncy Castle libraries from v1.78.1 to v1.79

Bouncy Castle Libraries have been updated to v1.79

  • bcmail-jdk18on-1.79.jar
  • bcpg-jkd180n-1.79.jar
  • pcpkix-jkd180n-1.79.jar
  • bcprov-jkd180n-1.79.jar
  • bcutil-jkd180n-1.79.jar

SCR-1593

Summary: Update Nimbus JOSE+JWT

Update Nimbus JOSE+JWT from v9.41.2 to v10.0.2 in bundle com.nimbus

SCR-1592

Summary: Update Apache CXF

Update Apache CXF libraries from v3.5.10 to v.3.5.11 in bundle com.openexchange.soap.common

SCR-1591

Summary: Update Apache Commons Lang

Update Apache Commons Lang from v3.14.0 to v3.18.0 in target platform (com.openexchange.bundles)

SCR-1590

Summary: Update Apache Commons FileUpload

Update Apache Commons FileUpload from v1.5 to v1.6.0 in target platform (com.openexchange.bundles)

SCR-1589

Summary: Update Apache Commons BeanUtils

Update Apache Commons BeanUtils from v1.9.4 to v1.11.0 in target platform (com.openexchange.bundles)

Configuration

SCR-1594

Summary: New Configuration Property 'com.openexchange.admin.user.convertguest.default'

To configure a default handling for the convertguest flag unless specified explicitly in the create user operation, the new lean configuration property com.openexchange.admin.user.convertguest.default is introduced.

If true, an existing guest user with the same primary email address is converted implicitly, if false (default), a conflict is raised.

Can be defined through the config-cascade up to the 'context' scope.

SCR-1588

Summary: Changed limitations for images in snippets (signatures)

  • The new default value for existing "com.openexchange.mail.signature.maxImageSize" property is now set to 0 (zero). Thus effectively disabled per default.

  • The new default value for existing "com.openexchange.mail.signature.maxImageLimit" property is now set to 0 (zero). Thus effectively disabled per default.

  • Introduced new property "com.openexchange.mail.signature.maxTotalImageSize" having its default value set to 5 (5MB). It is reloadable and config-cascade aware.

Database

SCR-1595

Summary: Drop unused table "jsonCache"

Update Task com.openexchange.groupware.update.tasks.DropJsonCacheTableTask

Drop unused table "jsonCache" as well as referenced entries in "updatetask" table:

  • "com.openexchange.json.cache.impl.osgi.JsonCacheEnsureLatin1AsDefault"
  • "com.openexchange.json.cache.impl.osgi.JsonCacheAddOtherFieldsTask"
  • "com.openexchange.json.cache.impl.osgi.JsonCacheMediumTextTask"
  • "com.openexchange.json.cache.impl.osgi.JsonCacheAddInProgressFieldTask"
  • "com.openexchange.json.cache.impl.osgi.JsonCacheCreateTableTask"

8.41.52

3rd Party Libraries/License Change

SCR-1582

Summary: Upgraded JSoup library

Upgraded JSoup library from v1.19.1 to v1.21.1 in target platform (com.openexchange.bundles)

SCR-1581

Summary: Updated bucket4j library

Updated bucket4j library (Java rate-limiting library based on token-bucket algorithm) from v8.7.0 to v8.10.1 in bundle com.openexchange.common

API - HTTP-API

SCR-1586

Summary: New Parameter 'user' for Action 'resolve' in Module 'chronos'

The resolve action in module chronos of the HTTP API is extended by the new optional parameter user, through which the identifier of the calendar user can be specified.

If an event is found, it'll be returned under the perspective of this user, i.e. having an appropriate parent folder identifier assigned. The current session user still needs to have appropriate access rights for the resolved event, though.

See the documentation for further details.

Behavioral Changes

SCR-1585

Summary: User copy improvements

The user copy feature got improved:

  • App passwords
  • Contact accounts
  • (Secondary) mail accounts
  • (Generic) use count
  • Snippets

will now also be copied.

https://gitlab.open-xchange.com/appsuite/platform/core/-/issues/265

Configuration

SCR-1588

Summary: Changed limitations for images in snippets (signatures)

  • The new default value for existing "com.openexchange.mail.signature.maxImageSize" property is now set to 0 (zero). Thus effectively disabled per default.

  • The new default value for existing "com.openexchange.mail.signature.maxImageLimit" property is now set to 0 (zero). Thus effectively disabled per default.

  • Introduced new property "com.openexchange.mail.signature.maxTotalImageSize" having its default value set to 5 (5MB). It is reloadable and config-cascade aware.

SCR-1584

Summary: New Property 'com.openexchange.calendar.includeCreatorInFreeBusy'

To control whether the entity that originally created a conflicting event is included in free/busy results, even if event details cannot be accessed by the requesting user, the lean configuration property com.openexchange.calendar.includeCreatorInFreeBusy is introduced. Possible values are:

  • never - Never expose the created by information in foreign events of free/busy results.
  • resources-only - Include the created by information in foreign events of free/busy results of resource attendees, only.
  • always - Always expose the created by information in foreign events of free/busy results.

It defaults to always for backwards compatibility, is reloadable, and can be defined through the config-cascade.

Although there has already been a similar switch for App Suite UI io.ox/calendar//freeBusyStrict to show/hide these details from foreign events, this middleware property controls the exposure of the "created by" information at API level, so should be used in favor of the UI setting.

8.40.56

3rd Party Libraries/License Change

SCR-1577

Summary: Updated OSGi target platform bundles

Updated the following OSGi target platform bundles

  • org.eclipse.osgi.util_3.7.300.v20231104-1118.jar updated to org.eclipse.osgi.util_3.7.400.v20250516-0916.jar
  • org.eclipse.osgi_3.20.0.v20240509-1421.jar updated to org.eclipse.osgi_3.23.100.v20250514-1759.jar

Configuration

SCR-1576

Summary: New properties to control number of tombstone records

In order to control how many tombstone records are persisted per calendar account, the following new lean configuration properties are introduced, each applicable for the corresponding calendar provider and defaulting to a value of 2500 unless overridden:

com.openexchange.calendar.ical.maxEventTombstones = 2500
com.openexchange.calendar.google.maxEventTombstones = 2500

A value of -1 disables the limit. Both properties are reloadable and config-cascade aware.

See the property documentation for further details.

8.39.64

API - HTTP-API

SCR-1573

Summary: New option 'identifiers' for 'folders?action=notify'

In order to support arbitrary permissions beyond context-internal entities, the notify action in module folders is extended by the possibility to reference the targeted recipients also by their identifier, as used in the corresponding permissions.

Therefore, the request body accepts an additional string array named identifiers, where the identifiers of the users or groups that shall be notified can be specified.

See the HTTP API documentation for further details.

SCR-1571

Summary: Exposed parameter 'trackAttendeeUsage' for 'chronos?action=new' and 'chronos?action=update'

The new and update actions in module chronos will now evaluate the optional parameter trackAttendeeUsage.

It can be used to configure whether newly added attendees from creations and updates should be tracked automatically, which includes adding new entries in the collected contacts folder for new external calendar users (utilizing the contact collector service), as well as incrementing the use counts for already known internal and external entities (using the object use count service). Defaults to true, hence needs to be disabled explicitly.

See the HTTP API documentation for further details.

Configuration

SCR-1574

Summary: New property 'com.openexchange.mail.crossContextPermissions'

In order to enable cross-context folder permissions / mailbox ACLs, the new lean configuration property com.openexchange.mail.crossContextPermissions is introduced, defaulting to false. It can be defined through the config-cascade and is reloadable. It should only be enabled if all contexts of the deployment access the same mail server, and requires further preconditions like a configured mail login resolver service.

Clients are able to discover the actual value via JSlob path io.ox/mail//crossContextPermissions.

See the property documentation, as well as the feature documentation for further details.

SCR-1572

Summary: New parameter 'com.openexchange.calendar.storage.separateTransactionForSequenceIds'

In order to control whether a separate database transaction should be used for generating sequential identifiers, or if id generation should be performed within the surrounding transaction of the calendar storage operation, the new lean configuration property com.openexchange.calendar.storage.separateTransactionForSequenceIds is introduced.

Using a separate transaction can help to minimize the duration of the row lock in the sequence table, especially when many conflicting accesses for a single context are to be expeceted, e.g. during mass imports of calendar data. However, an additional database connection is used, and any already incremented counters won't be part of a potential rollback, then.

The property defaults to false, is reloadable, but not config-cascade aware.

See the property documentation for further details.

8.38.77

3rd Party Libraries/License Change

SCR-1570

Summary: Updated Netty libraries from v4.1.119 to v4.1.121

Updated Netty libraries from v4.1.119 to v4.1.121 in bundle io.netty

  • netty-buffer-4.1.121.Final.jar
  • netty-codec-4.1.121.Final.jar
  • netty-codec-dns-4.1.121.Final.jar
  • netty-codec-http2-4.1.121.Final.jar
  • netty-codec-http-4.1.121.Final.jar
  • netty-codec-socks-4.1.121.Final.jar
  • netty-common-4.1.121.Final.jar
  • netty-handler-4.1.121.Final.jar
  • netty-handler-proxy-4.1.121.Final.jar
  • netty-resolver-4.1.121.Final.jar
  • netty-resolver-dns-4.1.121.Final.jar
  • netty-transport-4.1.121.Final.jar
  • netty-transport-native-unix-common-4.1.121.Final.jar
  • netty-transport-classes-epoll-4.1.121.Final.jar = netty
  • netty-transport-native-epoll-4.1.121.Final.jar = netty
  • netty-transport-classes-kqueue-4.1.121.Final.jar = netty
  • netty-transport-native-kqueue-4.1.121.Final.jar

SCR-1569

Summary: Updated lettuce library from v6.5.5 to v6.6.0

Updated lettuce library from v6.5.5 to v6.6.0 in bundle io.lettuce

SCR-1562

Summary: Updated Jackson libraries from v2.18.1 to v2.19.0 in target platfom

Updated several libraries to update Jackson libraries from v2.18.1 to v2.19.0

Target platform bundles (com.open-xchange.bundles)

  • jackson-annotations-2.18.1.jar replaced with jackson-annotations-2.19.0.jar
  • jackson-core-2.18.1.jar replaced with jackson-core-2.19.0.jar
  • jackson-databind-2.18.1.jar replaced with jackson-databind-2.19.0.jar
  • jackson-dataformat-cbor-2.18.1.jar replaced with jackson-dataformat-cbor-2.19.0.jar
  • jackson-dataformat-xml-2.18.1.jar replaced with jackson-dataformat-xml-2.19.0.jar
  • jackson-datatype-jsr310-2.18.1.jar replaced with jackson-datatype-jsr310-2.19.0.jar
  • jackson-datatype-jsr310-2.18.1.jar replaced with jackson-datatype-jsr310-2.19.0.jar
  • jackson-datatype-jsr353-2.18.1.jar replaced with jackson-datatype-jsr353-2.19.0.jar
  • jackson-jakarta-rs-base-2.18.1.jar replaced with jackson-jakarta-rs-base-2.19.0.jar
  • jackson-jakarta-rs-json-provider-2.18.1.jar replaced with jackson-jakarta-rs-json-provider-2.19.0.jar
  • jackson-jakarta-rs-xml-provider-2.18.1.jar replaced with jackson-jakarta-rs-xml-provider-2.19.0.jar
  • jackson-module-jakarta-xmlbind-annotations-2.18.1.jar replaced with jackson-module-jakarta-xmlbind-annotations-2.19.0.jar
  • jackson-module-jaxb-annotations-2.18.1.jar replaced with jackson-module-jaxb-annotations-2.19.0.jar

Bundle com.ctc.wstx

  • woodstox-core-7.0.0.jar replaced with woodstox-core-7.1.0.jar

Bundle org.yaml.snakeyaml

  • snakeyaml-2.3.jar replaced with snakeyaml-2.4.jar

API - HTTP-API

SCR-1567

Summary: Option "notification" when Granting Deputy Permissions

The new action in module deputy of the HTTP API is extended with an optional notification object where the transport and optional message can be specified by the client, in the same way as when a folder is shared, e.g.:

{
    [...]
    "notification": {
        "transport": "mail",
        "message": "the message"
    }
}

If set, a notification mail is generated and sent to the deputy user.

See the documentation for details.

SCR-1561

Summary: Introduced 'move' action for contacts/addressbooks

Introduced addressbooks?action=move / contacts?action=move to move contacts

Gitlab issue https://gitlab.open-xchange.com/appsuite/platform/core/-/issues/234

SCR-1453

Summary: New parameter "sortByUseCount" for "search" action in module "resource"

The action search in module resource of the HTTP API is extended with an additional, optional parameter named {}sortByUseCount. If {}true, found resources are implicitly sorted based on the individual use count number of the requesting user, in descending order (most frequently resources first), e.g. when being used during auto-complete operations of resource participants while creating new appointments.

See also the API documentation for further details.

API - Java

SCR-1560

Summary: Interface changes for contact move

com.openexchange.contact.provider.folder.FolderReadWriteContactsAccess:

  • new method List<Contact> moveContacts(String targetFolderId, String sourceFolderId, List<String> contactIds, long clientTimestamp) throws OXException;

com.openexchange.contact.provider.composition.IDBasedContactsAccess:

  • changed method List<ContactID> restoreContacts(List<ContactID> contactsIds, long clientTimestamp) throws OXException;
  • new method List<Contact> moveContacts(String targetFolderId, String sourceFolderId, List<String> contactIds, long clientTimestamp) throws OXException;

com.openexchange.contact.provider.composition.TrashFolderAwareContactsAccess:

  • changed method List<ContactID> restoreContacts(List<ContactID> contactsIds, long clientTimestamp) throws OXException;

com.openexchange.contact.storage.ContactStorage:

  • new method void move(Session session, String targetFolderId, String sourceFolderId, String id, Date lastRead, Date now) throws OXException;
  • new method void move(Session session, String targetFolderId, String sourceFolderId, String[] ids, Date lastRead, Date now) throws OXException;

com.openexchange.contact.ContactService:

  • new method List<Contact> moveContacts(Session session, String targetFolderId, String sourceFolderId, String[] contactIds, Date lastRead) throws OXException;
  • new method Contact moveContact(Session session, String targetFolderId, String sourceFolder, String contactId, Date lastRead) throws OXException;

Gitlab issue https://gitlab.open-xchange.com/appsuite/platform/core/-/issues/234

API - SOAP

SCR-1568

Summary: New "notification" Element when Granting Deputy Permissions

The grant call of the SOAP API "http://soap.admin.openexchange.com/OXDeputyPermissionsService" for deputy permissions management is extended with an optional notification element where the transport and optional message can be specified, e.g.:

  <soap:grant>
     <soap:notification>
        <xsd:transport>mail</xsd:transport>
        <xsd:message>the message</xsd:message>
     </soap:notification>
     [...]
  </soap:grant>

If set, a notification mail is generated and sent to the deputy user.

Behavioral Changes

SCR-1565

Summary: Redis connector now uses a pool of shared connections

The Open-Xchange Redis Connector now supports two operation modes for the pool of connections to Redis end-point(s).

  • com.openexchange.redis.connection.pool.mode Allows the values shared and dedicated. dedicated lets Redis Connector use a common connection pool for the "connection per thread" operation mode. An individual connection is only used by one thread at the same time. shared lets Redis Connector use a connection pool that manages shared connections. Thus, a single connection is concurrently used by multiple threads at the same time. This fully leverages the NIO and asynchronous capabilities of the underlying Lettuce client library, saves I/O overhead and gives better performance. Therefore, the default value for this property is shared. Not reloadable and not config-cascade aware.

  • com.openexchange.redis.connection.pool.numSharedConnections Specifies the max. number of shared connections that are managed in the connection pool running with shared mode. The default value for this property is 8. Not reloadable and not config-cascade aware.

Configuration

SCR-1564

Summary: New Configuration Property 'com.openexchange.calendar.externalConflictChecksTimeout'

The new lean configuration property com.openexchange.calendar.externalConflictChecksTimeout is introduced.

It configures the maximum time (in milliseconds) to wait for conflict check results from external sources like iCalendar subscriptions. A value of 0 disables external conflict checks during appointment creation or update completely.

It is reloadable and config-cascade aware, and default to 10000 (10 seconds).

See the documentation for further details.

SCR-1559

Summary: Changed com.openexchange.contact.trashFolder.enabled default value

Changed com.openexchange.contact.trashFolder.enabled default value to true

Database

SCR-1566

Summary: Update Task to Clear Empty Categories for Contacts

Update Task com.openexchange.groupware.update.tasks.ContactClearEmptyCategoriesTask

In order to remove categories values that accidentally got stored as [] in the database, the blocking update task

com.openexchange.groupware.update.tasks.ContactClearEmptyCategoriesTask

is introduced.

SCR-1563

Summary: Introduced update task to reset pflag for contacts

Introduced the update task com.openexchange.groupware.update.tasks.ResetContactPflagUpdateTask to reset prior set pflags for folder with id 6 (system folder), 16 (guest folder) and for folder of type 2 (public). 

8.37.72

General

SCR-1556

Summary: Upgraded MySQL-Connector-J from v.8.3.0 to v9.2.0

Upgraded MySQL-Connector-J from v.8.3.0 to v9.2.0 in traget platform (com.openexchange.bundles)

3rd Party Libraries/License Change

SCR-1553

Summary: Upgraded JSoup library from v1.17.2 to v1.19.1

Upgraded JSoup library from v1.17.2 to v1.19.1 in target platform (com.openexchange.bundles)

SCR-1552

Summary: Upgraded GSON from v2.10.1 to v2.12.1

Upgraded the GSON library from v2.10.1 to v2.12.1 in target platform (com.openexchange.bundles)

SCR-1551

Summary: Added new Failsafe library to target platform

Added new Failsafe v3.3.2 library to target platform (com.openexchange.bundles). Failsafe is a lightweight, zero-dependency library for handling failures in Java,

  • failsafe-3.3.2.jar

API - HTTP-API

SCR-1558

Summary: New parameter 'dontResolveEntities' for 'chronos?action=new'

The new action in module chronos is extended by a new, optional parameter {}dontResolveEntities{}.

Normally, all attendees in an event are resolved to internal entities by their calendar user address URI implicitly, and all resolved users will share the created organizer event copy automatically. Now if this new parameter is set to {}true{}, all entities besides the current calendar user are not resolved treated as external entities, i.e. these appointments will effectively only be created for and visible to the targeted folder's calendar user in App Suite.

See the documentation and HTTP API documentation for further details.

Behavioral Changes

SCR-1565

Summary: Redis connector now uses a pool of shared connections

The Open-Xchange Redis Connector now supports two operation modes for the pool of connections to Redis end-point(s).

  • com.openexchange.redis.connection.pool.mode Allows the values shared and dedicated. dedicated lets Redis Connector use a common connection pool for the "connection per thread" operation mode. An individual connection is only used by one thread at the same time. shared lets Redis Connector use a connection pool that manages shared connections. Thus, a single connection is concurrently used by multiple threads at the same time. This fully leverages the NIO and asynchronous capabilities of the underlying Lettuce client library, saves I/O overhead and gives better performance. Therefore, the default value for this property is shared. Not reloadable and not config-cascade aware.

  • com.openexchange.redis.connection.pool.numSharedConnections Specifies the max. number of shared connections that are managed in the connection pool running with shared mode. The default value for this property is 8. Not reloadable and not config-cascade aware.

Configuration

SCR-1534

Summary: Introduced 'autodelete_contacts' & 'autodelete_contacts_editable' capability and config-path / jslob

Introduced autodelete_contacts capability to indicate if contacts in contact trash folder are auto-deleted after a configurable retention period. The retention period is announced via configuration path modules/contacts/autodelete/retentiondays and jslob io.ox/contacts//autodelete/retentiondays.

Setting is editable by user if property com.openexchange.contact.autodelete.editable is set to true. This is announced by autodelete_contacts_editable capability, configuration path modules/contacts/autodelete/editable and jslob io.ox/contacts//autodelete/editable.

Related issue: [https://gitlab.open-xchange.com/appsuite/platform/core/-/issues/182]

SCR-1533

Summary: Added properties for contact auto-delete feature

Added reloadable and config-cascade-aware lean properties:

  • {}com.openexchange.contact.autodelete.enabled{}, default {}true{}. Defines whether the contacts in contact trash folder are auto-deleted.
  • {}com.openexchange.contact.autodelete.retentionDays{}, default {}30{}. Defines the retention days for the auto-delete feature.
  • {}com.openexchange.contact.autodelete.editable{}, default {}true{}. Defines whether the auto-delete retention days interval is editable by the user.

Related issue: [https://gitlab.open-xchange.com/appsuite/platform/core/-/issues/182]

Database

SCR-1554

Summary: Rename contact trash folder to maintain consistency across the modules

Update Task com.openexchange.groupware.update.tasks.OXFolderTreeRenameContactTrashTask

Existing contact trash folder with preliminary name Deleted contacts are renamed to Trash to maintain consistency across the modules

com.openexchange.groupware.update.tasks.OXFolderTreeRenameContactTrashTask

Related issues:

8.36.36

3rd Party Libraries/License Change

SCR-1537

Summary: Updated Netty libraries from v4.1.115 to v4.1.119

Updated Netty libraries from v4.1.115 to v4.1.119 in bundle io.netty

  • netty-buffer-4.1.119.Final.jar
  • netty-codec-4.1.119.Final.jar
  • netty-codec-dns-4.1.119.Final.jar
  • netty-codec-http2-4.1.119.Final.jar
  • netty-codec-http-4.1.119.Final.jar
  • netty-codec-socks-4.1.119.Final.jar
  • netty-common-4.1.119.Final.jar
  • netty-handler-4.1.119.Final.jar
  • netty-handler-proxy-4.1.119.Final.jar
  • netty-resolver-4.1.119.Final.jar
  • netty-resolver-dns-4.1.119.Final.jar
  • netty-transport-4.1.119.Final.jar
  • netty-transport-native-unix-common-4.1.119.Final.jar

SCR-1536

Summary: Updated Caffeine caching library

Updated Caffeine caching library from v3.1.8 to v3.2.0 in bundle com.google.guava

API - HTTP-API

SCR-1520

Summary: New restore action for addressbook endpoint

Introduced new /addressbooks?action=restore to restore trashed contacts.

SCR-1516

Summary: Added hardDelete parameter to contacts delete

In order to avoid the trashing mechanism for contacts when activated, we added a hardDelete paramter to the contacts/addressbooks delete requests.

API - Java

SCR-1519

Summary: Added hardDelete to FolderReadWriteContactsAccess

In order to avoid the trashing mechanism for contacts when activated, we added boolean hardDelete paramter to the FolderReadWriteContactsAccess interface for deleteContact and deleteContacts.

SCR-1518

Summary: Added restoreContact to FolderReadWriteContactsAccess

In order to be able to restore a contact we added the following method to the FolderReadWriteContactsAccess interface:

void restoreContact(ContactID contactId, Contact contact, ServerSession session, long clientTimestamp)

SCR-1517

Summary: Added hardDelete to InternalContactsAccess Interface

In order to avoid the trashing mechanism for contacts when activated, we added boolean hardDelete paramter to the InternalContactsAccess interface.

CLT

SCR-1528

Summary: New Option "convert-guest" in "createuser" Commandline Tool

The command-line interface createuser is extended with an additional option to automatically pick up and convert an existing guest user in the context matching the otherwise conflicting primary email address of the user being created:

--convert-guest booleanvalue : The flag whether it desired to convert an existent guest user to a regular user in case there is already a guest user associated with given primary E-Mail address

See https://documentation.open-xchange.com/main/middleware/command_line_tools/user/createuser.html for further details.

Configuration

SCR-1532

Summary: Introduced 'contact_trash' capability and config-path / jslob

Introduced contact_trash capability to indicate if a trash folder for contacts is available for the user. The folder identifier is announced via configuration path modules/contacts/folder/trash and jslob io.ox/contacts//folder/trash

Related issue: https://gitlab.open-xchange.com/appsuite/platform/core/-/issues/154

SCR-1523

Summary: New property com.openexchange.contact.trashFolder.enabled

Introduced new lean boolean property:

  • com.openexchange.contact.trashFolder.enabled If enabled, contacts deleted without the hardDelete parameter are moved to the trash folder instead of being deleted. Default value is {}false{}. Reloadable and config-cascade aware.

Database

SCR-1526

Summary: New origin column for prg_contacts and del_contacts

Update Task com.openexchange.groupware.update.tasks.ContactsAddOriginColumnTask

Add origin column to prg_contacts/del_contacts table to save information about the origin folder of a contact that has been moved to the trash:

origin VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL

8.35.68

API - SOAP

SCR-1529

Summary: New "convertguest" Element for "create" in "OXUserService"

Effective: 8.35.68 and later

The create element within the SOAP body of OXUserService is extended with an additional element to automatically pick up and convert an existing guest user in the context matching the otherwise conflicting primary email address of the user being created:

<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:create>
     [...]
         <soap:convertguest>...</soap:convertguest>
      </soap:create>
   </soapenv:Body>
</soapenv:Envelope>

8.35.66

CLT

SCR-1528

Summary: New Option "convert-guest" in "createuser" Commandline Tool

Effective: applies to the 8.35 release line

The command-line interface createuser is extended with an additional option to automatically pick up and convert an existing guest user in the context matching the otherwise conflicting primary email address of the user being created:

--convert-guest booleanvalue : The flag whether it desired to convert an existent guest user to a regular user in case there is already a guest user associated with given primary E-Mail address

See https://documentation.open-xchange.com/main/middleware/command_line_tools/user/createuser.html for further details.

API - HTTP-API

SCR-1489

Summary: New additional folder field 'com.openexchange.carddav.url' (id 3221)

Effective: applies to the 8.35 release line

The "detailed folder data" model of the HTTP API is extended by the additional folder field com.openexchange.carddav.url with column id 3221. The read only field is available for address book folders that are synchronizable via CardDAV, and points to the actual collection's endpoint as used by CardDAV clients.

See the documentation for further details.

Behavioral Changes

SCR-1490

Summary: Change of Key Format used for Redis Cache

Effective: applies to the 8.35 release line

For the Redis instance dedicated to caching purposes, operation mode Cluster may be used to scale out the Redis service horizontally. Doing so, the keyspace of the stored data is distributed evenly among the available Redis nodes. Technically, every master node in the cluster is responsible for certain hash slots. These slots are the underlying unit of sharding and calculated dynamically from the targeted key(s). Based on that, a command is routed based on its key's hash slot to the corresponding Redis node. If more than one node is targeted by a single command (e.g. DEL or MGET), single commands are executed in a fork/join manner against the correct Redis nodes automatically.

In order to prevent commands targeting multiple keys being distributed among multiple nodes, most of the cache keys that are actually associated with a certain OX context are changed so that the context identifier becomes the designated part of the key where the hash slot is calculated for, by surrounding it with curly braces (\{ and \}). For example, a typical key used to cache user data changes from ox-cache:usr:v1:5:12 to ox-cache:usr:v1:\{5\}:12

Due to this change, existing cached values using the previous key format will no longer be used when a rolling upgrade is performed, and will evict eventually (after com.openexchange.cache.v2.defaultExpirationSeconds, one hour by default). During this period, an increased memory usage will be noticeable after the middleware containers were updated. Therefore it is important that Redis is configured with an appropriate max-memory policy, especially if there's not much headroom left regarding the available usage. Alternatively, one can also flush all cached data once after the upgrade (using the FLUSHALL or FLUSHDB command manually).

SCR-1487

Summary: Health Check extended by Redis Cache

Effective: applies to the 8.35 release line

The health check of core middleware is extended with an check named redis.cache for the Redis connector attached to the instance used for caching purposes. It automatically becomes enabled once a Redis cache instance is configured via com.openexchange.redis.cache.enabled=true, and performs an operational check via PING command when called.

Like other checks, it can explicitly be disabled by including redis.cache in the value of property com.openexchange.health.skip. Or, to enable it, but not account its status to the overall result, it can be added to com.openexchange.health.ignore.

See the documentation for further details.

Changed defaults

SCR-1495

Summary: Disable Global Folder Cache by Default

Effective: applies to the 8.35 release line

Whether the so called "global folder cache" is enabled or not can be controlled via property com.openexchange.folderstorage.cache.enableGlobalFolderCache.

To avoid redundancies with the low-level database folder cache, its default value will change from true to false.

The absence of the additional caching layer will lower the memory requirements, as well as reduce the number of issued commands towards the Redis cache pod(s). However, since raw folder data is now always post-processed dynamically, this may lead to a slightly increased load on the middleware pods depending on client access patterns.

Configuration

SCR-1488

Summary: New Property com.openexchange.carddav.url

Effective: applies to the 8.35 release line

In order to display the CardDAV endpoint of address book collections to users in App Suite, a new lean configuration property named com.openexchange.carddav.url is introduced. Through this property, a URL template can be specified using the variables [hostname] and [folderId].

The property can be defined through the config-cascade and is reloadable. It defaults to https://[hostname]/carddav/[folderId].

See the property documentation for further details.

Database

SCR-1468

Summary: Add table for webauthn data

Effective: applies to the 8.35 release line

In order to implement webauthn for multifactor and authentication, a database table needs to be created to store the public key, signature count, and additional relevant data about the authenticator.

Create a table within the oxdatabase shards:

CREATE TABLE web_authn
    `cid` int(11) DEFAULT NULL,
    `id` int(11) DEFAULT NULL,
    `deviceId` varchar(100) NOT NULL,
    `keyId` varchar(500) NOT NULL,
    `userId` varchar(100) DEFAULT NULL,
    `name` varchar(100) DEFAULT NULL,
    `login` varchar(100) DEFAULT NULL,
    `publicKey` varchar(1000) DEFAULT NULL,
    `attestation` varchar(10000) DEFAULT NULL,
    `clientData` varchar(2000) DEFAULT NULL,
    `counter` int(11) DEFAULT NULL,
    `compromised` bit(1) DEFAULT NULL,
    `isMultifactor` bit(1) DEFAULT NULL,
    `discoverable` bit(1) DEFAULT NULL,
    `lastUsed` datetime DEFAULT NULL,
    `enabled` bit(1) DEFAULT NULL,
    PRIMARY KEY (cid,id,deviceId),
    KEY `web_authn_id_IDX` (`cid`) USING BTREE
    ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

Packaging/Bundles

SCR-1491

Summary: Bundle to allow new MFA registrations using WebAuthn instead of U2F

Effective: applies to the 8.35 release line

Added new bundle com.openexchange.webauthn to allow new MFA registrations using WebAuthn instead of U2F. Also already providing code to implement webauthn as a "full" authentication service. The new bundle has been added to open-xchange-multifactor package.

8.33

General

SCR-1482

Summary: Added redis.tls chart value

Effective: applies to the 8.35 release line

Whether to use TLS to connect to the Redis endpoint can now be configured using redis.tls.enabled and redis.cache.tls.enabled.

SCR-1480

Summary: Updated lettuce library from v6.5.0 to v6.5.1

Effective: applies to the 8.35 release line

Updated lettuce library from v6.5.0 to v6.5.1 in bundle io.lettuce

  • lettuce-core-6.5.1.RELEASE.jar

3rd Party Libraries/License Change

SCR-1481

Summary: Updated Fabric8 libraries from v6.10.0 to v6.13.4

Effective: applies to the 8.35 release line

Updated Fabric8 libraries from v6.10.0 to v6.13.4 in "io.fabric8.kubernetes" bundle

  • kubernetes-client-6.13.4.jar
  • kubernetes-client-api-6.13.4.jar
  • kubernetes-httpclient-jdk-6.13.4.jar
  • kubernetes-model-admissionregistration-6.13.4.jar
  • kubernetes-model-apiextensions-6.13.4.jar
  • kubernetes-model-apps-6.13.4.jar
  • kubernetes-model-autoscaling-6.13.4.jar
  • kubernetes-model-batch-6.13.4.jar
  • kubernetes-model-certificates-6.13.4.jar
  • kubernetes-model-common-6.13.4.jar
  • kubernetes-model-coordination-6.13.4.jar
  • kubernetes-model-core-6.13.4.jar
  • kubernetes-model-discovery-6.13.4.jar
  • kubernetes-model-events-6.13.4.jar
  • kubernetes-model-extensions-6.13.4jar
  • kubernetes-model-flowcontrol-6.13.4.jar
  • kubernetes-model-gatewayapi-6.13.4.jar
  • kubernetes-model-metrics-6.13.4.jar
  • kubernetes-model-networking-6.13.4.jar
  • kubernetes-model-node-6.13.4.jar
  • kubernetes-model-policy-6.13.4.jar
  • kubernetes-model-rbac-6.13.4.jar
  • kubernetes-model-resource-6.13.4.jar
  • kubernetes-model-scheduling-6.13.4.jar
  • kubernetes-model-storageclass-6.13.4.jar

SCR-1479

Summary: Updated Netty libraries from v4.1.114 to v4.1.115

Effective: applies to the 8.35 release line

Updated Netty libraries from v4.1.114 to v4.1.115 in bundle io.netty

  • netty-buffer-4.1.115.Final.jar
  • netty-codec-4.1.115.Final.jar
  • netty-codec-dns-4.1.115.Final.jar
  • netty-codec-http2-4.1.115.Final.jar
  • netty-codec-http-4.1.115.Final.jar
  • netty-codec-socks-4.1.115.Final.jar
  • netty-common-4.1.115.Final.jar
  • netty-handler-4.1.115.Final.jar
  • netty-handler-proxy-4.1.115.Final.jar
  • netty-resolver-4.1.115.Final.jar
  • netty-resolver-dns-4.1.115.Final.jar
  • netty-transport-4.1.115.Final.jar
  • netty-transport-native-unix-common-4.1.115.Final.jar

Configuration

SCR-1485

Summary: New options for Redis Connector

Effective: applies to the 8.35 release line

Added new lean options for the Redis connector

  • com.openexchange.redis.connection.pool.newConnectionIfWaitExceeded Specifies whether to establish a new connection if waiting for an available connection in pool is exceeded. Default value is "true". Neither reloadable, nor config-cascade aware

  • com.openexchange.redis.cluster.periodicTopologyRefreshMillis Defines the interval in milliseconds for periodic refreshing of the the cluster topology. Only effective if connecting against a Redis Cluster; e.g. "com.openexchange.redis.mode" is set to "cluster". Default value is "600000". Neither reloadable, nor config-cascade aware

SCR-1477

Summary: New property to select default collection for new contacts via iOS / CardDAV

Effective: applies to the 8.35 release line

In the Contacts App on iOS, it is not possible to pick a certain folder while creating a new contact within the CardDAV account. Instead, the iOS client creates new contacts in a somehow randomly chosen folder of the account, which could also be the "Global Address Book" or the "Collected Contacts" folder, or even folders that are shared from others. Therefore, as the user cannot influence the target folder, an implicit workaround is in place so that new contacts are always created within the user's default contacts folder on App Suite. Within the iOS client, this is reflected after the next synchronization cycle as well.

To influence the applied fallback logic, the following lean configuration property is introduced:

com.openexchange.carddav.iosFallbackToDefaultCollectionForNewResources 

Possibly settings are:

  • always: New contacts are always created within the user's default contacts folder on App Suite
  • disabled: Contacts are created within the folder targeted by the client, but rejected on insufficient permissions
  • insufficientPermissions: Contacts are created within the folder targeted by the client, falling back to the user's default folder on insufficient permissions

It defaults to always so that contacts are created in the user's default contacts folder independently of which folder is targeted by the client.

The new property is reloadable and config-cascade-aware.

8.32

General

SCR-1473

Summary: Updated lettuce library from v6.4.0 to v6.5.0

Effective: applies to the 8.35 release line

Updated lettuce library from v6.4.0 to v6.5.0in bundle io.lettuce

  • lettuce-core-6.5.0.RELEASE.jar

3rd Party Libraries/License Change

SCR-1476

Summary: Updated Jackson libraries from v2.16.1 to v2.18.1 in target platfom

Effective: applies to the 8.35 release line

Updated several libraries to update Jackson libraries from v2.16.1 to v2.18.1

Target platform bundles (com.open-xchange.bundles)

  • stax2-api-4.2.1.jar replaced with stax2-api-4.2.2.jar
  • jackson-annotations-2.16.1.jar replaced with jackson-annotations-2.18.1.jar
  • jackson-core-2.16.1.jar replaced with jackson-core-2.18.1.jar
  • jackson-databind-2.16.1.jar replaced with jackson-databind-2.18.1.jar
  • jackson-dataformat-cbor-2.16.1.jar replaced with jackson-dataformat-cbor-2.18.1.jar
  • jackson-dataformat-xml-2.16.1.jar replaced with jackson-dataformat-xml-2.18.1.jar
  • jackson-datatype-jsr310-2.16.1.jar replaced with jackson-datatype-jsr310-2.18.1.jar
  • jackson-datatype-jsr310-2.16.1.jar replaced with jackson-datatype-jsr310-2.18.1.jar
  • jackson-datatype-jsr353-2.16.1.jar replaced with jackson-datatype-jsr353-2.18.1.jar
  • jackson-jakarta-rs-base-2.16.1.jar replaced with jackson-jakarta-rs-base-2.18.1.jar
  • jackson-jakarta-rs-json-provider-2.16.1.jar replaced with jackson-jakarta-rs-json-provider-2.18.1.jar
  • jackson-jakarta-rs-xml-provider-2.16.1.jar replaced with jackson-jakarta-rs-xml-provider-2.18.1.jar
  • jackson-module-jakarta-xmlbind-annotations-2.16.1.jar replaced with jackson-module-jakarta-xmlbind-annotations-2.18.1.jar
  • jackson-module-jaxb-annotations-2.16.1.jar replaced with jackson-module-jaxb-annotations-2.18.1.jar

Bundle com.ctc.wstx

  • woodstox-core-6.5.1.jar replaced with woodstox-core-7.0.0.jar

Bundle org.yaml.snakeyaml

  • snakeyaml-2.2.jar replaced with snakeyaml-2.3.jar

SCR-1472

Summary: Updated Netty libraries from v4.1.112 to v4.1.114

Effective: applies to the 8.35 release line

Updated Netty libraries from v4.1.112 to v4.1.114 in bundle io.netty

  • netty-buffer-4.1.112.Final.jar
  • netty-codec-4.1.112.Final.jar
  • netty-codec-dns-4.1.112.Final.jar
  • netty-codec-http2-4.1.112.Final.jar
  • netty-codec-http-4.1.112.Final.jar
  • netty-codec-socks-4.1.112.Final.jar
  • netty-common-4.1.112.Final.jar
  • netty-handler-4.1.112.Final.jar
  • netty-handler-proxy-4.1.112.Final.jar
  • netty-resolver-4.1.112.Final.jar
  • netty-resolver-dns-4.1.112.Final.jar
  • netty-transport-4.1.112.Final.jar
  • netty-transport-native-unix-common-4.1.112.Final.jar

Configuration

SCR-1475

Summary: New property to configure SSO Logout when OX Sessions are closed

Effective: applies to the 8.35 release line

In order to configure after which session removal events an OpenID Connect session is also closed on the provider side, the following lean configuration property is introduced:

com.openexchange.oidc.opLogoutOnSessionRemoval

It specifies an optional comma-separated list of certain session removal events for which the logout endpoint of the OP should be invoked as well to terminate the OIDC session. This does not affect regular/explicit, client-initiated logout flows where the OP is always included as per com.openexchange.oidc.ssoLogout. Also, sessions spawned using the Resource Owner Password Credentials Grant are not considered.

Configurable removal events include:

  • expired - The session is removed after being idle/unused for a certain duration
  • user_closed - Another session is removed explicitly by the user (usually via session management API)
  • admin_closed - A session is removed explicitly via an administrative interface (e.g. close sessions commandline utility or REST API)

The property is empty by default, reloadable, and not config-cascade-aware. See also the documentation for further details.

SCR-1470

Summary: Added new lean property to control detection of inline images

Effective: applies to the 8.35 release line

Added new lean property com.openexchange.mail.detectInlineImageByDispositionOnly that controls whether to detect inline images solely by its value for "Content-Disposition" header (required to be "inline") and to ignore any file name information (e.g through "filename" parameter).

SCR-1462

Summary: Added new property to track Redis operation taking longer than a configured threshold

Effective: applies to the 8.35 release line

Added new lean property com.openexchange.redis.operationExecutionTimeThreshold to track Redis operation taking longer than a configured threshold. Default value is 0 (zero), therefore disabled by default. Not reloadable and not config-cascade aware.

8.31

Configuration

SCR-1462

Summary: Added new property to track Redis operation taking longer than a configured threshold

Effective: applies to the 8.35 release line

Added new lean property com.openexchange.redis.operationExecutionTimeThreshold to track Redis operation taking longer than a configured threshold. Default value is 0 (zero), therefore disabled by default. Not reloadable and not config-cascade aware.

8.31

API - Java

SCR-1460

Summary: Constructor change in com.openexchange.passwordchange.common.AbstractPasswordChangeService

Effective: applies to the 8.35 release line

With dropping legacy caching bundles com.openexchange.caching.*, the constructor in com.openexchange.passwordchange.common.AbstractPasswordChangeService changed as c.o.caching.CacheService is no longer available

CLT

SCR-1464

Summary: Dropped 'checkconfigconsistency' CLT

Effective: applies to the 8.35 release line

With removal of legacy com.openexchange.caching bundles, the checkconfigconsistency CLT is no longer needed

Configuration

SCR-1466

Summary: Allow specifying the name of the HTTP header that forwards the originating remote port

Effective: applies to the 8.35 release line

Introduced new lean property "com.openexchange.server.portHeader" specifying the name of the HTTP header that forwards the originating remote port. Default value is "X-Forwarded-Port". It is neither reloadable nor config-cascade aware.

SCR-1465

Summary: New configuration property com.openexchange.push.dovecot.unregisterAfterDelete

Effective: applies to the 8.35 release line

Depending on the setup, it may not be suitable to attempt a de-registration of active push listeners on the mail server during user- or context deletion. Therefore, a new lean configuration property is introduced:

com.openexchange.push.dovecot.unregisterAfterDelete

It defaults to true so that current semantics are not changed. The new configuration property is reloadable, yet not config-cascade aware.

SCR-1462

Summary: Added new property to track Redis operation taking longer than a configured threshold

Effective: applies to the 8.35 release line

Added new lean property com.openexchange.redis.operationExecutionTimeThreshold to track Redis operation taking longer than a configured threshold. Default value is 0 (zero), therefore disabled by default. Not reloadable and not config-cascade aware.

SCR-1461

Summary: Dropped legacy cache service properties

Effective: applies to the 8.35 release line

Dropped properties (referenced in open-xchange-core/debian/postinst):

  • com.openexchange.caching.jcs.remoteInvalidationForPersonalFolders
  • com.openexchange.caching.jcs.enabled
  • jcs.region.*

Dropped from system.properties:

  • UserConfigurationStorage
  • Cache

Frontend

SCR-1469

Summary: New Setting for Preferred Calendar User Address

Effective: applies to the 8.35 release line

Introduced the JSLob entry io.ox/calendar/preferredAddress to let the end user control which email address is assigned to the corresponding attendee in calendar events, to e.g. avoid exposing of an unwanted email address. The value of the entry can always be set by the user, however is limited to the known aliases of the user.

Packaging/Bundles

SCR-1459

Summary: Dropped com.openexchange.caching.* bundles

Effective: applies to the 8.35 release line

As all caches are transformed to com.openexchange.cache.v2 implementation, the legacy cache implementation in com.openexchange.caching and com.openexchange.caching.events bundles is dropped

8.30

3rd Party Libraries/License Change

SCR-1452

Summary: Moved Java Data Objects (JDO) API to target platform

Effective: applies to the 8.35 release line

Moved the Java Data Objects (JDO) API formerly held in bundle com.openexchange.common to target platform bundles managed in com.openexchange.bundles.

Therefore, the target platform (com.openexchange.bundles) has been extended by the libraries:

  • glassfish-corba-omgapi-4.2.4.jar
  • jdo-api-3.2.1.jar

API - HTTP-API

SCR-1456

Summary: Removed "messaging"-related APIs

Effective: applies to the 8.35 release line

Removed HTTP-API paths

  • messaging/account
  • messaging/message
  • messaging/service

API - Java

SCR-1458

Summary: Upgrade to Java 21

Effective: applies to the 8.35 release line

Middleware core will be upgraded to Java 21. This means that each bundle's required execution environment will now be JaveSE-21, and a compatible runtime JRE must be used.

Configuration

SCR-1457

Summary: Removed "messaging"-related properties

Effective: applies to the 8.35 release line

Removed "messaging"-related properties

  • "com.openexchange.messaging.enabled"

SCR-1454

Summary: New configuration property "com.openexchange.cache.v2.redis.disableHashExpiration"

Effective: applies to the 8.35 release line

Breaking Change

A new lean configuration property com.openexchange.cache.v2.redis.disableHashExpiration is temporarily introduced for increased compatibility with older versions of Redis.

The property optionally disables field expiration of hash keys. If set to true, no HEXPIRE commands are invoked after setting values in hashes, resulting in persistent values that will only be removed explicitly by the application, or due to a general maxmemory eviction policy of Redis like allkeys-lru.

It should therefore only be enabled if a dedicated Redis instance for cache-purposes is used (see com.openexchange.redis.cache.enabled)!

The property is neither config-cascade aware nor reloadable. It is only available for a temporary grace period and will be removed again in a future version - therefore it should be considered as deprecated from the beginning.

SCR-1442

Summary: Removed 'hazelcast-data-holding' and 'hazelcast-lite-member' roles

Effective: applies to the 8.35 release line

Since the core middleware no longer depends on Hazelcast, the roles hazelcast-data-holding and hazelcast-lite-member defined in the core-mw Helm chart are no longer needed. As a result, they will be removed in version 6.0.0.

However, OX Documents, which is still included in the middleware image, relies on Hazelcast and requires a headless service. Therefore, the headless service from the hazelcast-data-holding role has been moved to a new role named documents.

Please note that custom node definitions (scaling.nodes) must include this new role. Otherwise, the headless service will not be deployed, and OX Documents bundles will fail to start.

For more information, refer to the chart documentation.

Packaging/Bundles

SCR-1455

Summary: Removed "messaging"-related functionality

Effective: applies to the 8.35 release line

Through removal of "messaging"-related functionality the following bundles and packages were dropped:

Bundles

  • com.openexchange.messaging
  • com.openexchange.messaging.generic
  • com.openexchange.messaging.json
  • com.openexchange.messaging.rss
  • com.openexchange.messaging.sms

Packages

  • open-xchange-messaging
  • open-xchange-messaging-sms

SCR-1427

Summary: Removed "MsService" and Parent Bundle "com.openexchange.ms"

Effective: applies to the 8.35 release line

The service com.openexchange.ms.MsService as well as its parent bundle com.openexchange.ms are no longer used and had been deprecated along with SCR-1342. Now they're removed from middleware core.

8.29

3rd Party Libraries/License Change

SCR-1451

Summary: Updated Google Guava from v33.2.1 to v33.3.0

Effective: applies to the 8.35 release line

Updated Google Guava from v33.2.1 to v33.3.0 in bundle com.google.guava

SCR-1450

Summary: Removed org.eclipse.osgi.services helper bundle

Effective: applies to the 8.35 release line

Removed org.eclipse.osgi.services helper bundle in favor of individual org.osgi.service.X bundles

SCR-1448

Summary: Upgraded dnsjava (an implementation of DNS in Java)

Effective: applies to the 8.35 release line

Upgraded dnsjava from v3.5.3 to v3.6.1 in target platform (com.openexchange.bundles)

SCR-1440

Summary: Updated OSGi target platform bundles

Effective: applies to the 8.35 release line

Updated the following OSGi target platform bundles

  • org.apache.felix.gogo.runtime_1.1.4.v20210111-1007.jar updated to org.apache.felix.gogo.runtime_1.1.6.jar
  • org.eclipse.osgi.util_3.7.200.v20230103-1101.jar updated to org.eclipse.osgi.util_3.7.300.v20231104-1118.jar
  • org.eclipse.osgi_3.18.400.v20230509-2241.jar updated to org.eclipse.osgi_3.20.0.v20240509-1421.jar

SCR-1433

Summary: Updated lettuce library from v6.3.2 to v6.4.0

Effective: applies to the 8.35 release line

Updated lettuce library from v6.3.2 to v6.4.0in bundle io.lettuce

  • lettuce-core-6.4.0.RELEASE.jar

SCR-1432

Summary: Updated Netty libraries from v4.1.111 to v4.1.112

Effective: applies to the 8.35 release line

Updated Netty libraries from v4.1.111 to v4.1.112 in bundle io.netty

  • netty-buffer-4.1.112.Final.jar
  • netty-codec-4.1.112.Final.jar
  • netty-codec-dns-4.1.112.Final.jar
  • netty-codec-http2-4.1.112.Final.jar
  • netty-codec-http-4.1.112.Final.jar
  • netty-codec-socks-4.1.112.Final.jar
  • netty-common-4.1.112.Final.jar
  • netty-handler-4.1.112.Final.jar
  • netty-handler-proxy-4.1.112.Final.jar
  • netty-resolver-4.1.112.Final.jar
  • netty-resolver-dns-4.1.112.Final.jar
  • netty-transport-4.1.112.Final.jar
  • netty-transport-native-unix-common-4.1.112.Final.jar

API - HTTP-API

SCR-1406

Summary: Added an client defined expiration time to /token?action=acquireToken

Effective: applies to the 8.35 release line

The parameter expiry was added to the request acquireToken. Thus, a client is able to define an individual expiry for a login token, see also /login?action=redeemToken. The expiry parameter will only be considered if the value is less the configured value through com.openexchange.tokenlogin.maxIdleTime

SCR-1405

Summary: Renamed parameter in '/login?action=redeemToken'

Effective: applies to the 8.35 release line

The parameter secret has been renamed to appId since it is more fitting to the nature of the parameter. secret can still be used, but is deprecated from now on. It will be removed in upcoming releases.

API - Java

SCR-1428

Summary: Deprecation of JCS-based "CacheService"

Effective: applies to the 8.35 release line

After a new caching implementation has been introduced with com.openexchange.cache.v2.CacheService, the previously used, JCS-based com.openexchange.caching.CacheService is now deprecated and is scheduled for removal in a later release. Until then, the interfaces are available and the service is basically still usable, however, without remote cache invalidation features.

SCR-1192

Summary: Removed com.openexchange.cluster.timer.ClusterTimerService

Effective: applies to the 8.35 release line

Removed com.openexchange.cluster.timer.ClusterTimerService

API - RMI

SCR-1430

Summary: Added new RMI API for deputy permissions management

Effective: applies to the 8.35 release line

Added new RMI API "com.openexchange.admin.rmi.OXDeputyPermissionsInterface" for deputy permissions management offering methods:

  • grantDeputyPermission() Grants a new deputy permission

  • updateDeputyPermission() Updates an existent deputy permission

  • revokeDeputyPermission() Revokes/deletes an existent deputy permission

  • getDeputyPermission() Retrieves a certain deputy permission

  • listAll() Lists all deputy permissions for a given context

API - SOAP

SCR-1431

Summary: Added new SOAP API for deputy permissions management

Effective: applies to the 8.35 release line

Added new SOAP API "http://soap.admin.openexchange.com/OXDeputyPermissionsService" for deputy permissions management offering methods:

  • grant() Grants a new deputy permission

  • update() Updates an existent deputy permission

  • revoke() Revokes/deletes an existent deputy permission

  • get() Retrieves a certain deputy permission

  • list() Lists all deputy permissions for a given context

Behavioral Changes

SCR-1425

Summary: Removed Replacement of "email 1" by "default sender address"

Effective: applies to the 8.35 release line

Previously, the middleware implicitly injected the configured "default sender address" into the "email 1" field of contacts representing internal users, in case com.openexchange.notification.fromSource was set to defaultSenderAddress. This handling goes back to a workaround that was introduced to make this mail address available in Outlook through the former OXtender integration.

This caused different issues in the past, e.g. unexpected values in the global address book, incorrect search results, multiple users with apparently the same mail addresses etc.

As the client for which the workaround has been introduced has passed away a long time ago, this implicit mail address replacement is now removed, as it is obviously no longer necessary. Consequently, the provisioned "email 1" address is now always exposed in user contact objects through all APIs, regardless of aforementioned configuration setting com.openexchange.notification.fromSource.

So for cases where a different default sender address has been set before in a user's mail settings, the behavioral change would be that this address will now no longer be displayed for the associated contact object, but the actually stored value for "email 1".

Configuration

SCR-1449

Summary: Added DNS configuration options for MX records look-up on ISPDB auto-config detection

Effective: applies to the 8.35 release line

Added new lean DNS configuration options for MX records look-up on ISPDB auto-config detection

  • com.openexchange.mail.autoconfig.ispdb.dns.resolverHost The optional host name for the DNS server on MX record look-up. If not specified system's default DNS service is used.

  • com.openexchange.mail.autoconfig.ispdb.dns.resolverPort The optional port number for the DNS server on MX record look-up. If not specified default port (53 UDP) is used.

SCR-1441

Summary: New Configuration Property "com.openexchange.oidc.staySignedIn"

Effective: applies to the 8.35 release line

If the default OIDC backend implementation is used, sessions created through OpenID Connect have the "stay signed in" marker set to false by default.

This can now be changed through configuration parameter com.openexchange.oidc.staySignedIn, and has an impact on the cookie- and OX session lifetime. If true, cookies will be decorated with the max. age as configured via com.openexchange.cookie.ttl. Also, the maximum idle time of OX sessions will be aligned to com.openexchange.sessiond.sessionLongLifeTime. If set to false, cookies will use session lifetime, and the maximum OX session idle time follows com.openexchange.sessiond.sessionDefaultLifeTime.

The lean property defaults to false, is reloadable, and not config-cascade aware.

SCR-1438

Summary: Removed all xing properties

Effective: applies to the 8.35 release line

The following xing properties have been removed:

  • com.openexchange.oauth.xing
  • com.openexchange.oauth.xing.apiKey
  • com.openexchange.oauth.xing.apiSecret
  • com.openexchange.oauth.xing.consumerKey
  • com.openexchange.oauth.xing.consumerSecret
  • com.openexchange.subscribe.socialplugin.xing
  • com.openexchange.subscribe.socialplugin.xing.autorunInterval

SCR-1435

Summary: Removed option from Redis configuration

Effective: applies to the 8.35 release line

Removed option "com.openexchange.redis.resilientDatabase" from Redis configuration in favor of possibility to specify a dedicated Redis instance for volatile (cache) data; see SCR-1434.

Thus instead of specifying a dedicated database for resilient data (such as sessions), the administrator is supposed to deploy dedicated Redis instance for volatile (cache) data.

SCR-1434

Summary: Added option to Redis configuration to specify a separate instance

Effective: applies to the 8.35 release line

Added new lean option "com.openexchange.redis.cache.enabled" to Redis configuration to specify a separate instance dedicated for volatile (cache) data. This option is neither reloadable nor config-cascade aware.

With that option set to "true", the administrator may specify further Redis options for that special Redis instance through using the "cache" infix; e.g.

com.openexchange.redis.cache.enabled=true
com.openexchange.redis.cache.mode=standalone
com.openexchange.redis.cache.hosts=localhost:6379
 ...

SCR-1407

Summary: Replaced 'tokenlogin-secrets' file with lean configuration

Effective: applies to the 8.35 release line

Breaking Change The file tokelogin-secrets has been removed.

The file tokenlogin-secrets was used to define "secret" applications for which a token login was allowed. Such "secrets" could be enriched with parameters, controlling flows in the middleware. The file was not reloadable nor config cascade aware. Therefore, replaced the file with config cascade aware and reloadable properties. The properties are defined as followed:

  • com.openexchange.tokenlogin.applications specifies the application identifiers to use, split by comma. These IDs were formerly knwon as "secrets". No default value is defined. The IDs are used to define application specific behaviour through the other properties
  • com.openexchange.tokenlogin.[applicationId].accessPassword specifies whether or not the user's password is part of the response when redeeming the token. Default is false.
  • com.openexchange.tokenlogin.[applicationId].copyParameters specifies whether or not to copy all session parameters into the cloned session, that is created during the token login action. Default is false
  • com.openexchange.tokenlogin.[applicationId].announceId specifies whether or not to announce the application identifier to a client within the JSLob. Default is false.
  • com.openexchange.tokenlogin.[applicationId].parameters specifies additional key-value pairs for the application, paired by equals, split by semicolon. Default is empty. Mainly kept for legacy reasons.

Database

SCR-1436

Summary: Introduced update task for removing xing accounts

Effective: applies to the 8.35 release line

Introduced the update task com.openexchange.oauth.impl.internal.groupware.RemoveXingAccountsUpdateTask for removing xing accounts.

Packaging/Bundles

SCR-1437

Summary: Removed xing bundles

Effective: applies to the 8.35 release line

Removed xing bundles:

  • com.openexchange.xing
  • com.openexchange.xing.access
  • com.openexchange.xing.json
  • com.openexchange.subscribe.xing
  • com.openexchange.oauth.xing
  • com.openexchange.halo.xing

Package definitions have been removed as well:

  • open-xchange-xing-json

SCR-1429

Summary: Added new bundle for deputy permissions management via SOAP

Effective: applies to the 8.35 release line

Added new bundle "com.openexchange.admin.soap.deputy" for deputy permissions management via SOAP. That new bundle has been added to "open-xchange-admin-soap" package.

SCR-1426

Summary: Removed "FilteringObjectStreamFactory" Service and parent Bundle "com.openexchange.serialization"

Effective: applies to the 8.35 release line

The service com.openexchange.serialization.FilteringObjectStreamFactory as well as its parent bundle com.openexchange.serialization are no longer used and had been deprecated along with SCR-1421. Now they're removed from middleware core.

8.28

3rd Party Libraries/License Change

SCR-1420

Summary: Removed xmlbeans-2.6.0 library

Effective: applies to the 8.35 release line

The library xmlbeans-2.6.0 has known vulnerabilities. Since it is no longer used in the Middleware, the library is removed from target platform (com.openexchange.bundles)

SCR-1419

Summary: Upgraded ROME library for RSS and Atom feeds

Effective: applies to the 8.35 release line

Upgraded ROME library for RSS and Atom feeds from v1.0 to v1.19.0 in bundle com.openexchange.messaging.rss

SCR-1415

Summary: Updated Google Guava from v33.0.0 to v33.2.1

Effective: applies to the 8.35 release line

Updated Google Guava from v33.0.0 to v33.2.1 in bundle com.google.guava

API - Java

SCR-1421

Summary: Deprecation of "FilteringObjectStreamFactory" Service

Effective: applies to the 8.35 release line

The service com.openexchange.serialization.FilteringObjectStreamFactory has been introduced to secure serialization routines in the first version of the "Realtime" framework.

Therefore, it should now be considered as deprecated, and is scheduled to be removed along with its parent bundle com.openexchange.serialization in a future release.

Behavioral Changes

SCR-1390

Summary: Introduced an admin based rate limit for provisioning calls

Effective: applies to the 8.35 release line

Up until now the provisioning apis (soap, rmi, clt) were not rate limited which could lead to downtimes in case a client provisioned too fast. This is especially painful in case multiple customers are on the same platform and could influence each other.

To prevent such scenarios in the future we introduced a new rate limit which is applied per admin. It effects all provisioning apis and is checked during the authentication process.

The limit is applied in constant 1 minute timeframes and can be configured for all admins or a single ones in case one would like to introduce different limits for different admins.

For this the following lean properties were introduced as well:

com.openexchange.rmi.rate.limit.default=-1
com.openexchange.rmi.rate.limit.[admin] 

See https://gitlab.open-xchange.com/app-suite-platform-1/provisioning/-/issues/1 for details

Configuration

SCR-1422

Summary: Removed unused cache regions from cache.ccf file

Effective: applies to the 8.35 release line

Removed unused cache regions from cache.ccf file since according caches are now held in Redis storage or refactored to a local (Guava) cache.

Removed regions are:

  • OXFolderCache
  • OXFolderQueryCache
  • GlobalFolderCache

SCR-1416

Summary: Changed default value for property "com.openexchange.net.ssl.protocols"

Effective: applies to the 8.35 release line

Changed default value for lean property "com.openexchange.net.ssl.protocols" from "TLSv1, TLSv1.1, TLSv1.2" to "TLSv1.2, TLSv1.3" following the recommendation to always use TLS 1.2 or higher

8.27

3rd Party Libraries/License Change

SCR-1409

Summary: Apache Commons Lang 2.6 removed from target platform

Effective: applies to the 8.35 release line

The library Apache Commons Lang 2.6 has been removed from the target platform. The code should be migrated to Apache Commons Lang 3.x.

All known dependencies have already been resolved in previous releases.

SCR-1404

Summary: Updated JCTools in target platform

Effective: applies to the 8.35 release line

Updated JCTools (Java Concurrency Tools for the JVM) from v4.0.3 to v4.0.5 in target platform

SCR-1394

Summary: Updated lettuce library from v6.3.1 to v6.3.2

Effective: applies to the 8.35 release line

Updated lettuce library from v6.3.1 to v6.3.2 in bundle io.lettuce

  • lettuce-core-6.3.2.RELEASE.jar

SCR-1393

Summary: Updated Netty libraries from v4.1.106 to v4.1.111

Effective: applies to the 8.35 release line

Updated Netty libraries from v4.1.106 to v4.1.111 in bundle io.netty

  • netty-buffer-4.1.111.Final.jar
  • netty-codec-4.1.111.Final.jar
  • netty-codec-dns-4.1.111.Final.jar
  • netty-codec-http2-4.1.111.Final.jar
  • netty-codec-http-4.1.111.Final.jar
  • netty-codec-socks-4.1.111.Final.jar
  • netty-common-4.1.111.Final.jar
  • netty-handler-4.1.111.Final.jar
  • netty-handler-proxy-4.1.111.Final.jar
  • netty-resolver-4.1.111.Final.jar
  • netty-resolver-dns-4.1.111.Final.jar
  • netty-transport-4.1.111.Final.jar
  • netty-transport-native-unix-common-4.1.111.Final.jar

SCR-1389

Summary: Removed jboss library

Effective: applies to the 8.35 release line

The library jboss-jms-api.jar is no longer needed. Therefore, it has been removed.

SCR-1212

Summary: Update BouncyCastle Libraries to Latest

Effective: applies to the 8.35 release line

Bouncy Castle Libraries have been updated to include several bug fixes.  Want to update Bouncy Libraries to version 1.78.1

  • bcmail-jdk18on-1.78.1.jar
  • bcpg-jkd180n-1.78.1.jar
  • pcpkix-jkd180n-1.78.1.jar
  • bcprov-ext REMOVED, use bcprov.  ext was extended support of old methods and no longer required
  • bcprov-jkd180n-1.78.1.jar
  • bcutil-jkd180n-1.78.1.jar

API - HTTP-API

SCR-1406

Summary: Added an client defined expiration time to /token?action=acquireToken

Effective: applies to the 8.35 release line

The parameter expiry was added to the request acquireToken. Thus, a client is able to define an individual expiry for a login token, see also /login?action=redeemToken. The expiry parameter will only be considered if the value is less the configured value through com.openexchange.tokenlogin.maxIdleTime

SCR-1405

Summary: Renamed parameter in '/login?action=redeemToken'

Effective: applies to the 8.35 release line

The parameter secret has been renamed to appId since it is more fitting to the nature of the parameter. secret can still be used, but is deprecated from now on. It will be removed in upcoming releases.

SCR-1403

Summary: New field 'priority' in Event model of HTTP API

Effective: applies to the 8.35 release line

The Event model of the HTTP API is extended by a new field named priority. Its value defines the relative priority of the calendar event with the following semantics (see RFC 5545, section 3.8.1.9 for further details):

This priority is specified as an integer in the range 0 to 9. A value of 0 specifies an undefined priority. A value of 1 is the highest priority. A value of 2 is the second highest priority. Subsequent numbers specify a decreasing ordinal priority. A value of 9 is the lowest priority.

SCR-1401

Summary: Removal of transport "websocket" from "pns" API

Effective: applies to the 8.35 release line

The transport "websocket" in "pns" API was marked as deprecated with SCR-1297. It is now removed with version 8.27.

Behavioral Changes

SCR-1412

Summary: Caches Transformed to Redis

Effective: applies to the 8.35 release line

In an iterative approach, more and more caches are being outsourced from middleware node-local caches (JCS), towards a centralized caching architecture using Redis.

Consequently, the memory requirements for the Redis pods are going to increase - with this, as well as in upcoming releases.

Therefore, it is recommended to increase the memory assigned to the Redis pods via Helm charts ({}resources.limits{} and/or {}resources.requests{}), and to monitor the memory consumption of the Redis pods closely, e.g. by utilizing the exposed metrics like {}redis_memory_used_dataset_bytes{}.

Configuration

SCR-1408

Summary: Added new config option controlling whether to use HTML on reply/forward if preferred

Effective: applies to the 8.35 release line

Added new lean config option: * com.openexchange.mail.useHtmlOnReplyForwardIfPreferred That boolean config option controls whether to use HTML on reply/forward to/of text-only E-Mails if HTML is chosen as preferred message format. Default value is false. That property is both - reloadable and config-cascade aware.

SCR-1383

Summary: New Property com.openexchange.redis.resilientDatabase

Effective: applies to the 8.35 release line

In order to configure an alternative database number for Redis/KeyDB, the following lean configuration property is introduced:

com.openexchange.redis.resilientDatabase

This property allows to configure an alternative database number to use for unrecoverable data like sessions that might be replayed to remote sites in sharded environments with multiple data centers ("Active/Active").

Especially, data stored there would be resilient when flushing the default database after recovering from failover situations.

Databases are only available for Redis stand-alone and Redis Master/Slave.

A negative number means no specific database.

The property defaults to -1, which means that no separate database number is used. It is neither reloadable, nor config-cascade-aware.

Database

SCR-1411

Summary: Added an account index to various calendar tables for improved look-up

Effective: applies to the 8.35 release line

Added an index for columns cid and account to following calendar tables for improved look-up:

  • calendar_event
  • calendar_event_tombstone
  • calendar_attendee
  • calendar_attendee_tombstone
  • calendar_alarm
  • calendar_alarm_trigger
  • calendar_conference

SCR-1402

Summary: New Column 'priority' for Database Tables 'calendar_event' and 'calendar_event_tombstone'

Effective: applies to the 8.35 release line

Update Task com.openexchange.chronos.storage.rdb.groupware.CalendarEventAddPriorityColumnTask

The database tables calendar_event and calendar_event_tombstone are extended with a new column as follows:

`priority` INT4 UNSIGNED DEFAULT NULL

This is done through the following update task:

com.openexchange.chronos.storage.rdb.groupware.CalendarEventAddPriorityColumnTask

Packaging/Bundles

SCR-1388

Summary: Removed obsolete bundle 'com.google.gdata'

Effective: applies to the 8.35 release line

The bundle com.google.gdata is no longer in use and therefore is removed, along with its reference from package/feature {}open-xchange-oauth{}.

8.26

API - HTTP-API

SCR-1399

Summary: Deprecate messaging-related functionality and APIs

Effective: applies to the 8.35 release line

The middleware used to provide a generic messaging service for different use cases like SMS or data from RSS feeds. However, these are no longer in use by App Suite UI, or got replaced with an alternative solution in the meantime.

Therefore, corresponding functionality as well as the following modules of the HTTP API should be considered as deprecated, and will be removed in a future version:

  • messaging/account
  • messaging/message
  • messaging/service

Configuration

SCR-1382

Summary: Added new lean property to specify SMTP chunk size

Effective: applies to the 8.35 release line

Added new lean property com.openexchange.smtp.chunksize (and com.openexchange.smtp.primary.chunksize respectively) to specify SMTP chunk size to use the SMTP extension for transmission of large messages; see RFC 3030. Default is 131072 (128KB). Reloadbale and config-cascade aware.

SCR-1386

Summary: Added new config options for webhook-based password change service

Effective: applies to the 8.35 release line

In order to configure the webhook-based password change service, the following properties have been introduced:

  • com.openexchange.passwordchange.webhook.enabled

    Enables the webhook-based password change service (default: false)

  • com.openexchange.passwordchange.webhook.endpoint

    The webhook endpoint

  • com.openexchange.passwordchange.webhook.username

    The optional basic auth username for the webhook endpoint

  • com.openexchange.passwordchange.webhook.password

    The optional basic auth password for the webhook endpoint

All properties are reloadable and config-cascade aware.

Database

SCR-1387

Summary: Introduced a new count table users_per_filestore for users using a certain file storage

Effective: applies to the 8.35 release line

Introduced users_per_context table in ConfigDB to have a direct access how many users use a certain file storage:

Table layout is:

CREATE TABLE `users_per_filestore` (
  `filestore_id` int(10) unsigned NOT NULL,
  `count` int(10) unsigned NOT NULL,
  PRIMARY KEY (`filestore_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

SCR-1424

Summary: Changes for "infostore_document" and "infostore" that are required to support MySQL 8.4

Effective: applies to the 8.35 release line

Update task com.openexchange.groupware.update.tasks.InfostoreDocumentDropForeignKey drops the foreign key from "infostore_document" table due to missing unique key in the referenced table "infostore" and adds an appropriate index instead.

8.25

3rd Party Libraries/License Change

SCR-1373

Summary: Deprecation of Apache Commons Lang 2.6

Effective: applies to the 8.35 release line

The Apache Commons Lang in version 2.6 will be removed from the target platform with version 8.26! As version 3.x (currently 3.14.0) of Apache Commons Lang is already available within the target platform please make sure to migrate your code to this version until the release of App Suite 8.26!

API - HTTP-API

SCR-1375

Summary: Added sort_first_name field to DistributionListMember

Effective: applies to the 8.35 release line

Each member of a distribution list now contains an additional field sort_first_name which provides a name which can be used for sorting by first name. This field works similar to the sort_first_name field of the contact itself.

Additionally the members are also sorted according to this field.

SCR-1372

Summary: Added virtual contact field column 'sort_first_name'

Effective: applies to the 8.35 release line

Added virtual contact field column sort_first_name with the column identifier 623.

In analogy to the sort_name column (607), which sorts by surname, this column id can be used to sort the contacts in a contact request by the first name, taking into account the YOMI names.

Configuration

SCR-1380

Summary: Added new config option to control if user's local part should be assumed

Effective: applies to the 8.35 release line

Added new lean config option com.openexchange.imap.assumeUserLocalPartForSharedFolderPath to control if user's local part should be assumed when determining the path for a shared IMAP folder; e.g. assume "jane.doe" instead of "jane.doe@invalid.com". Default is false. Reloadable and config-cascade aware.

SCR-1378

Summary: Removal of Property com.openexchange.redis.enabled

Effective: applies to the 8.35 release line

After Redis becoming mandatory for core middleware services (SCR-1310, SCR-1330, SCR-1342 and furthers), the previously available switch com.openexchange.redis.enabled is no longer needed and therefore removed.

That means that the middleware will no longer start or work properly without configured Redis instance. By default, a standalone Redis instance on localhost:6379, is used. See property documentation for further details.

Consequently, in the "core-mw" Helm chart, the previously available enabled switch in the redis section is removed as well. That means that, unless configured differently via hosts, a fallback standalone Redis service is deployed by default.

Database

SCR-1319

Summary: Drop oauth-provider tables

Effective: applies to the 8.35 release line

Update tasks com.openexchange.groupware.update.tasks.DropOAuthGrantTableTask and com.openexchange.groupware.update.tasks.DropAuthCodeTableTask drop the tables oauth_grant and authCode from contextdb. The changesets 8.x:oauth_client:drop and 8.x:oauth_client_uri:drop drop the tables oauth_client and oauth_client_uri from globaldb.

8.24

3rd Party Libraries/License Change

SCR-1366

Summary: Updated Spring Framework

Effective: applies to the 8.35 release line

Updated Spring Framework from v5.3.21 to v6.1.4 in bundle com.openexchange.xml

  • spring-beans-6.1.4.jar
  • spring-core-6.1.4.jar
  • spring-jcl-6.1.4.jar

API - Java

SCR-1367

Summary: Slightly incompatible update to BasicAuthenticatorPluginInterface

Effective: applies to the 8.35 release line

In order to gain more flexibility in case of multiple Plugins implementing BasicAuthenticatorPluginInterface and to introduce Context-Admin capability for regular users using the provisioning APIs, the return type of the three methods

  • isOwnerOfContext()
  • isMasterOfContext()
  • isMasterOfContext()

will be changed from the primitive type boolean to Optional<Boolean> also supporting the third state empty to ignore the result and skip to the next plugin.

API - REST

SCR-1368

Summary: New REST API endpoint /admin/v1/contexts/pre-assemble to pre-assemble contexts

Effective: applies to the 8.35 release line

The concept of pre-assembled contexts consists of the asynchronous pre-creation of deactivated contexts that will be reused (and adapted to the provided settings) during the usual createcontext call. Pre-assembled contexts are characterized by being deactivated with reason_id equals 666 and their name beginning with the preassembled- prefix followed by an UUID.

In order to pick up pre-assembled contexts during regular provisioning operations, context skeletons need to be inserted into the database first. This can be achieved in two ways, by calling a REST API or via a background job. 

The REST API is located at http://oxhost:8009/admin/v1/contexts/pre-assemble. Pre-assembled contexts can be generated by a POST request using master authentication with a body containing a JSON object describing the schema name and how many context skeletons should be created. Optionally you can add the id of the filestore that should be used for the pre-assembled context by defining filestore_id parameter. 

Example:

POST /admin/v1/contexts/pre-assemble HTTP/1.1
Content-Type: application/json
Authorization: Basic amFuOmphbg==
User-Agent: PostmanRuntime/7.36.3
Accept: */*
Cache-Control: no-cache
Postman-Token: 3992936c-9d95-43c6-beb7-8b110e0088e2
Host: devenv.oxmw.io:8009
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 41

{
    "number":4,"schema": "oxuserdb_5"
}

HTTP/1.1 200 OK
Server: grizzly/2.4.4
X-Robots-Tag: none
Content-Type: application/json; charset=UTF-8
Content-Length: 52

{
    "contextIds": [
        11832,
        11833,
        11834,
        11835
    ],
    "errors": []
}

The response contains a JSON array of identifiers of the created pre-assembled contexts at field contextIds. Any errors that might have occurred when inserting the data are supplied in the errors array as well. In case of fatal errors, a response status different from  HTTP 200 will be returned depending on the error that occurred. Please have a look at the full REST API description of the endpoint for more details.

Configuration

SCR-1370

Summary: Added option to Redis configuration to specify a compression method

Effective: applies to the 8.35 release line

Added lean property to Redis configuration to specify a compression method

  • com.openexchange.redis.compressionType The compression type to globally compress/decompress any data written to/read from Redis end-point according to specified type. Allowed type: snappy, gzip, deflate and none. Enabling or disabling compression is backward-compatible; meaning any previously written uncompressed data can still be decoded as well as any previously compressed data (provided that compression gets turned off later on). Default value is none. Neither config-cascade aware nor reloadable.

  • com.openexchange.redis.minimumCompressionSize The minimum size for a data chunk in bytes for being considered for compression. Only effective if "com.openexchange.redis.compressionType" is set to not "none".

SCR-1360

Summary: New lean properties for background job to create pre-assembled contexts

Effective: applies to the 8.35 release line

New lean and non-reloadable properties to configure the background job that creates pre-assembled contexts:

  • com.openexchange.admin.context.preassembly.job.enabled, defaults to false. Whether background job is active or not
  • com.openexchange.admin.context.preassembly.job.schedule, defaults to Mon-Sun 0-4. The pattern specifying when to execute context the pre-assemble job. The default time zone of the Java virtual machine is assumed, which is typically the system's default time zone; unless the user.timezone property is set otherwise.
  • com.openexchange.admin.context.preassembly.job.contextsPerSchema, defaults to 100. Configures the number of pre-assembled contexts that should exist per schema after the job was executed. This number will never be exceeded by using the background job. Of course it is possible to exceed this limit by using the REST API.
  • com.openexchange.admin.context.preassembly.job.contextLimitFactor, defaults to 0.9. Configures the maximum filling level of schemas when adding pre-assembled contexts via periodic background job, as a factor of CONTEXTS_PER_SCHEMA. I. e. pre-assembly is only performed until the total number of contexts exceeds <factor> * <contexts_per_schema>.

  • com.openexchange.admin.context.preassembly.job.frequency, defaults to 3600000 (1 hour). The frequency in milliseconds when to check for new job executions within configured schedule.

  • com.openexchange.admin.context.preassembly.job.executionDelay, defaults to 86400000 (1 day). The (minimum) delay between repeated executions of the pre-assembly job in milliseconds.

SCR-1331

Summary: Added lean property 'com.openexchange.admin.context.preassembly.enabled'

Effective: applies to the 8.35 release line

Added lean property com.openexchange.admin.context.preassembly.enabled to enable using pre-assembled contexts instead of creating new contexts. Pre-assembled contexts must exist in database before enabling! Defaults to false.

SCR-1292

Summary: Dropped the 'com.openexchange.drive.events.gcm.key' property

Effective: applies to the 8.35 release line

Dropped the com.openexchange.drive.events.gcm.key property. Introduced the com.openexchange.drive.events.fcm.keyPath property as a replacement.

SCR-1290

Summary: Dropped the 'key' attribute in the 'pushClientConfig'

Effective: applies to the 8.35 release line

Dropped the key attribute in the pushClientConfig config file for the _type fcm. Introduced the keyPath attribute, which defines the full path of the FCM key file.

SCR-1289

Summary: Renamed .gcm. properties to .fcm.

Effective: applies to the 8.35 release line

Affected properties are:

  • com.openexchange.drive.events.gcm.enabled
  • com.openexchange.drive.events.gcm.clientId
  • com.openexchange.pns.transport.gcm.enabled.*

The new properties are now available under a new qualified name:

  • com.openexchange.drive.events.fcm.enabled
  • com.openexchange.drive.events.fcm.clientId
  • com.openexchange.pns.transport.fcm.enabled.*

Database

SCR-1288

Summary: Rename 'serviceId' and 'transport' values from GCM to FCM

Effective: applies to the 8.35 release line

Update Task com.openexchange.drive.events.fcm.groupware.RenameGCM2FCMUpdateTask com.openexchange.pns.transport.fcm.groupware.RenameGCM2FCMUpdateTask

Due to deprecation and end-of-life of GCM, we need to switch to FCM, hence the rename of the serviceId and transport values in the database.

Packaging/Bundles

SCR-1369

Summary: Removal of Kerberos Authentication

Effective: applies to the 8.35 release line

The Kerberos authentication integration that was available via supplementary package open-xchange-authentication-kerberos was removed.

See SCR-1315 for the deprecation with version 8.19.

SCR-1314

Summary: Introduced new FCM bundles

Effective: applies to the 8.35 release line

Added the following FCM-related bundles:

  • com.google.firebase
  • com.openexchange.drive.events.fcm
  • com.openexchange.pns.transport.fcm

SCR-1313

Summary: Removed GCM bundles

Effective: applies to the 8.35 release line

Removed the following GCM-related bundles:

  • com.google.android.gcm
  • com.openexchange.drive.events.gcm
  • com.openexchange.pns.transport.gcm

8.23

3rd Party Libraries/License Change

SCR-1362

Summary: Updated metadata-extractor

Effective: applies to the 8.35 release line

Updated 3rd party library metadata-extractor from v2.18.0 to v2.19.0 in bundle com.drew

SCR-1361

Summary: Updated Pushy library

Effective: applies to the 8.35 release line

Updated Pushy library from v0.15.2 to v0.15.4 in bundle com.eatthepath.pushy

SCR-1359

Summary: Updated a bunch of bundles in target platform

Effective: applies to the 8.35 release line

Updated the following bundles in target platform (com.openexchange.bundles):

Apache Mime4j

  • apache-mime4j-core-0.8.7.jar -> apache-mime4j-core-0.8.10.jar
  • apache-mime4j-dom-0.8.7.jar -> apache-mime4j-dom-0.8.10.jar
  • apache-mime4j-storage-0.8.7.jar -> apache-mime4j-storage-0.8.10.jar

Apache Commons

  • commons-net-3.9.0.jar -> commons-net-3.10.0.jar
  • commons-pool2-2.11.1.jar -> commons-pool2-2.12.0.jar
  • commons-text-1.10.0.jar -> commons-text-1.11.0.jar
  • commons-validator-1.6.jar -> commons-validator-1.8.0.jar

Various/other

  • dnsjava-3.5.2.jar -> dnsjava-3.5.3.jar
  • expiringmap-0.5.11.jar
  • fontbox-2.0.24.jar -> fontbox-2.0.30.jar
  • jctools-core-4.0.1.jar -> jctools-core-4.0.3.jar
  • joda-time-2.10.5.jar -> joda-time-2.12.7.jar
  • jsoup-1.16.1.jar -> jsoup-1.17.2.jar
  • pdfbox-2.0.24.jar -> pdfbox-2.0.30.jar
  • snappy-java-1.1.10.3.jar -> snappy-java-1.1.10.5.jar

SCR-1358

Summary: Updated Apache Commons Lang3 library

Effective: applies to the 8.35 release line

Updated Apache Commons Lang3 library from v3.12.0 to v3.14.0 in target platform (com.openexchange.bundles)

SCR-1357

Summary: Updated Apache Commons IO library

Effective: applies to the 8.35 release line

Updated Apache Commons IO library from v2.11.0 to v2.15.1 in target platform (com.openexchange.bundles)

SCR-1356

Summary: Updated Apache Commons Exec library

Effective: applies to the 8.35 release line

Updated Apache Commons Exec library from v1.3 to v1.4.0 in target platform (com.openexchange.bundles)

SCR-1355

Summary: Updated Apache Commons CLI library

Effective: applies to the 8.35 release line

Updated Apache Commons Codec library from v1.5.0 to v1.6.0 in target platform (com.openexchange.bundles)

SCR-1354

Summary: Updated Apache Commons Codec library

Effective: applies to the 8.35 release line

Updated Apache Commons Codec library from v1.15 to v1.16.1 in target platform (com.openexchange.bundles)

SCR-1353

Summary: Updated Apache Commons Compress library

Effective: applies to the 8.35 release line

Updated Apache Commons Compress library from v1.21 to v1.26.0 in target platform (com.openexchange.bundles)

SCR-1349

Summary: Upgraded MaxMind GeoIP Libraries

Effective: applies to the 8.35 release line

The following 3rd party libraries in bundle com.openexchange.geolocation.maxmind.binary are upgraded:

  • MaxMind GeoIP2 API from v2.12.0 to v2.17.0 (geoip2-2.12.0.jar)
  • MaxMind DB Reader from v1.2.2 to v2.1.0 (maxmind-db-2.1.0.jar)

SCR-1348

Summary: Updated Amazon Java SDK

Effective: applies to the 8.35 release line

Updated Amazon Java SDK from v1.12.487 to v1.12.661 in bundle com.amazonaws

SCR-1345

Summary: Updated Google Guava from v32.1.3 to v33.0.0

Effective: applies to the 8.35 release line

Updated Google Guava from v32.1.3 to v33.0.0 in bundle com.google.guava

Configuration

SCR-1365

Summary: Support new property for Sproxyd connector to specify connection lease timeout

Effective: applies to the 8.35 release line

Support new property for Sproxyd connector to specify connection lease timeout:

  • com.openexchange.filestore.sproxyd.connectionLeaseTimeout The connection lease timeout in milliseconds when waiting for a free connection in connection pool to become available. Default is 5 seconds (5000). Reloadable, but not config-cascade aware.

SCR-1351

Summary: New property com.openexchange.health.noServicesMissing.enabled

Effective: applies to the 8.35 release line

A new lean configuration property is introduced to activate an additional health check regarding internal service dependencies:

com.openexchange.health.noServicesMissing.enabled=false

It defaults to false for now hence needs to be enabled explicitly. Once enabled, the overall health check will only yield an UP result if all service/package dependencies are met. Therefore it is recommended to ensure that this is the case, i.e. the output of getmissingservices utility is empty.

The property is not config-cascade-aware, and not reloadable.

SCR-1350

Summary: Added possibility to have ZIP archive compiled for a certain module during a data export being spooled to a local disk

Effective: applies to the 8.35 release line

Added possibility to have ZIP archive compiled for a certain module being spooled to a local disk. Therefore, the following new lean properties were added:

  • com.openexchange.gdpr.dataexport.spoolToFile Whether to spool collected data to a ZIP archive held on local disk or to append directly to destination file storage. Default value: false. Neither reloadable nor config-cascade aware

  • com.openexchange.gdpr.dataexport.spoolDirectory The spool directory on disk to use for spooling. Requires that "com.openexchange.gdpr.dataexport.spoolToFile" is set to "true". if not set or specifies a non-existent, non-writable directory path, the default upload directory is used instead. Neither reloadable nor config-cascade aware

Packaging/Bundles

SCR-1347

Summary: Added new bundles for Redis-backed cache

Effective: applies to the 8.35 release line

Added new bundles (interface/API & implementation) for Redis-backed cache to open-xchange-core package:

  • com.openexchange.cache.v2
  • com.openexchange.cache.v2.redis

8.22

3rd Party Libraries/License Change

SCR-1344

Summary: Updated lettuce library from v6.2.6 to v6.3.1

Effective: applies to the 8.35 release line

Updated lettuce library from v6.2.6 to v6.3.1 in bundle io.lettuce

  • lettuce-core-6.3.1.RELEASE.jar

SCR-1343

Summary: Updated Netty libraries from v4.1.97 to v4.1.106

Effective: applies to the 8.35 release line

Updated Netty libraries from v4.1.97 to v4.1.106 in bundle io.netty

  • netty-buffer-4.1.106.Final.jar
  • netty-codec-4.1.106.Final.jar
  • netty-codec-dns-4.1.106.Final.jar
  • netty-codec-http2-4.1.106.Final.jar
  • netty-codec-http-4.1.106.Final.jar
  • netty-codec-socks-4.1.106.Final.jar
  • netty-common-4.1.106.Final.jar
  • netty-handler-4.1.106.Final.jar
  • netty-handler-proxy-4.1.106.Final.jar
  • netty-resolver-4.1.106.Final.jar
  • netty-resolver-dns-4.1.106.Final.jar
  • netty-transport-4.1.106.Final.jar
  • netty-transport-native-unix-common-4.1.106.Final.jar

SCR-1340

Summary: Updated Jackson & Fabric8 libraries

Effective: applies to the 8.35 release line

Updated Jackson libraries from v2.15.3 to v2.16.1 in target platfom

  • jackson-annotations-2.16.1.jar
  • jackson-core-2.16.1.jar
  • jackson-databind-2.16.1.jar
  • jackson-dataformat-cbor-2.16.1.jar
  • jackson-dataformat-xml-2.16.1.jar
  • jackson-dataformat-yaml-2.16.1.jar
  • jackson-datatype-jsr310-2.16.1.jar
  • jackson-datatype-jsr353-2.16.1.jar
  • jackson-jakarta-rs-base-2.16.1.jar
  • jackson-jakarta-rs-json-provider-2.16.1.jar
  • jackson-jakarta-rs-xml-provider-2.16.1.jar
  • jackson-module-jakarta-xmlbind-annotations-2.16.1.jar
  • jackson-module-jaxb-annotations-2.16.1.jar

Updated Fabric8 ibraries from v6.9.0 to v6.10.0 in "io.fabric8.kubernetes" bundle

  • kubernetes-client-6.10.0.jar
  • kubernetes-client-api-6.10.0.jar
  • kubernetes-httpclient-jdk-6.10.0.jar
  • kubernetes-model-admissionregistration-6.10.0.jar
  • kubernetes-model-apiextensions-6.10.0.jar
  • kubernetes-model-apps-6.10.0.jar
  • kubernetes-model-autoscaling-6.10.0.jar
  • kubernetes-model-batch-6.10.0.jar
  • kubernetes-model-certificates-6.10.0.jar
  • kubernetes-model-common-6.10.0.jar
  • kubernetes-model-coordination-6.10.0.jar
  • kubernetes-model-core-6.10.0.jar
  • kubernetes-model-discovery-6.10.0.jar
  • kubernetes-model-events-6.10.0.jar
  • kubernetes-model-extensions-6.10.0.jar
  • kubernetes-model-flowcontrol-6.10.0.jar
  • kubernetes-model-gatewayapi-6.10.0.jar
  • kubernetes-model-metrics-6.10.0.jar
  • kubernetes-model-networking-6.10.0.jar
  • kubernetes-model-node-6.10.0.jar
  • kubernetes-model-policy-6.10.0.jar
  • kubernetes-model-rbac-6.10.0.jar
  • kubernetes-model-resource-6.10.0.jar
  • kubernetes-model-scheduling-6.10.0.jar
  • kubernetes-model-storageclass-6.10.0.jar

SCR-1337

Summary: Updated bucket4j library

Effective: applies to the 8.35 release line

Updated bucket4j library (Java rate-limiting library based on token-bucket algorithm) from v7.0.0 to v8.7.0

API - HTTP-API

SCR-1305

Summary: Completely removed the ramp-up action

Effective: applies to the 8.35 release line

Completely removed the ramp-up action handling

API - Java

SCR-1339

Summary: Added methods in 'com.openexchange.admin.storage.interfaces.OXUserStorageInterface' for using pre-assembled contexts

Effective: applies to the 8.35 release line

Added methods

  • com.openexchange.admin.storage.interfaces.OXUserStorageInterface.changeModuleAccess(Context, int[], UserModuleAccess, Connection) - use an already established connection to change module access (already implemented with MW-2229)
  • com.openexchange.admin.storage.interfaces.OXUserStorageInterface.change(Context, User, Connection) - use an already established conntection to change user data (already implemented with MW-2229)
  • com.openexchange.admin.storage.interfaces.OXUserStorageInterface.updatePreassembledLogin2UserData(Context, User, Connection) - update pre-assembled dummy data in login2user table (implemented with MWB-2470)

SCR-1306

Summary: Completely removed the ramp-up APIs and services

Effective: applies to the 8.35 release line

Completely removed the ramp-up APIs and services

Behavioral Changes

SCR-1342

Summary: Use Redis-based pub/sub functionality in favor over Hazelcast-based topics/queues

Effective: applies to the 8.35 release line

Using Redis-based pub/sub functionality in favor over Hazelcast-based topics/queues. API-wise the former com.openexchange.ms.MsService is marked as deprecated and developers should use new com.openexchange.pubsub.PubSubService instead.

SCR-1330

Summary: Redis becoming mandatory for cluster-wide functions

Effective: applies to the 8.35 release line

In our step-wise approach of integrating Redis-based services into the middleware, we already introduced the Redis-backed session storage. With completion of the story "Redis by Default: Configuration, Documentation" (MW-2144), Redis will be enabled by default.

With "Switch Hazelcast Map Usages to New Service" (MW-2145) Redis will now be mandatory for many advanced features that make use of distributed states, when multiple middleware nodes are used in the cluster.

CLT

SCR-1336

Summary: Dropped argument from oxinstaller command-line tool

Effective: applies to the 8.35 release line

Dropped argument "--jkroute" from oxinstaller command-line tool

Configuration

SCR-1341

Summary: Added new lean property to possibly add Open-Xchange server information to HTTP responses

Effective: applies to the 8.35 release line

Added new lean property "com.openexchange.http.grizzly.addServerVersion" to possibly add Open-Xchange server information as "X-Open-Xchange-Server" HTTP header to responses. Default is "false". Neither reloadable nor config-cascade aware.

SCR-1338

Summary: Added new configuration options for session look-ups at remote sites

Effective: applies to the 8.35 release line

Added new lean configuration options for session look-ups at remote sites

  • com.openexchange.sessiond.redis.remote.ratelimit.overallMaxAccesses Specifies the max. number of overall remote site look-ups: not more than overallMaxAccesses per overallTimeWindowMillis. Default value is 60. Reloadable, but not config-cascade aware

  • com.openexchange.sessiond.redis.remote.ratelimit.overallTimeWindowMillis Specifies the time window for overall remote site look-ups: not more than overallMaxAccesses per overallTimeWindowMillis. Default value is 60000. Reloadable, but not config-cascade aware

  • com.openexchange.sessiond.redis.remote.ratelimit.maxRatePerClient Specifies the max. number of per-client remote site look-ups: not more than maxRatePerClient per timeWindowMillisPerClient. Default value is 10. Reloadable, but not config-cascade aware

  • com.openexchange.sessiond.redis.remote.ratelimit.timeWindowMillisPerClient Specifies the time window for per-client remote site look-ups: not more than maxRatePerClient per timeWindowMillisPerClient. Default value is 60000. Reloadable, but not config-cascade aware

SCR-1335

Summary: Dropped legacy property com.openexchange.server.backendRoute

Effective: applies to the 8.35 release line

Dropped legacy property com.openexchange.server.backendRoute from file server.properties.

This was no lean property, thus that property needs to be removed the old way.

SCR-1331

Summary: Added lean property 'com.openexchange.admin.usePreAssembledContexts'

Effective: applies to the 8.35 release line

Added lean property com.openexchange.admin.usePreAssembledContexts to enable using pre-assembled contexts instead of creating new contexts. Pre-assembled contexts musts exist in database before enabling! Defaults to false.

Database

SCR-1332

Summary: Added table 'context_lock' to configdb

Effective: applies to the 8.35 release line

Update Task com.openexchange.database.internal.change.custom.ServerCreateContextLockTable

Added table context_lock to configdb, used for claiming/locking pre-assembled contexts.

CREATE TABLE `context_lock` (
    `cid` INT(10) UNSIGNED NOT NULL,
    `claim` BINARY(16) NOT NULL,
    `timestamp` BIGINT(20) UNSIGNED NOT NULL,
    PRIMARY KEY(`cid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

Packaging/Bundles

SCR-1327

Summary: New soap request analyzer bundle

Effective: applies to the 8.35 release line

Introduced a new com.openexchange.admin.soap.request.analyzer bundle

8.21

3rd Party Libraries/License Change

SCR-1279

Summary: Upgraded javacc to 7.10.12

Effective: applies to the 8.35 release line

Upgraded the javacc library to version 7.10.12

API - HTTP-API

SCR-1333

Summary: Added action chronos/itip?action=decline_party_crasher

Effective: applies to the 8.35 release line

A new action, chronos/itip?action=decline_party_crasher, was added to the module chronos. The action enables the end user to decline the participation of an unknown calendar user (aka. "party crasher"), that responded to a certain event. The action triggers a CANCEL mail to the unknown calendar user. The CANCEL mail can be used by the unknown calendar user to (automatically) remove the appointment from her calendar. The action is defined as followed:

REQUEST:
PUT http://example.org/appsuite/api/chronos/itip?action=decline_party_crasher&session=1234xyz
{
  "com.openexchange.mail.conversion.fullname": "INBOX",
  "com.openexchange.mail.conversion.mailid": "1337",
  "com.openexchange.mail.conversion.sequenceid": "1.3"
}


RESPONSE:
{
    "data":
    {
        "recipient":
        {
            "uri": "mailto:partyCrasher@example.org",
            "cn": "Party Crasher",
            "email": "partyCrasher@example.org"
        },
        "status": "SENT"
    },
    "timestamp": 1704188470824
}

API - HTTP-REST

SCR-1295

Summary: Introduced a new REST interface for managing logging configuration

Effective: applies to the 8.35 release line

New REST endpoints are introduced in order to manage logging configuration via HTTP: The REST endpoints are registered under the /admin path and requires admin BASIC AUTH.

The new API routes are.

/admin/v1/logconf/system/loggers
/admin/v1/logconf/system/logger/
/admin/v1/logconf/session//loggers/
/admin/v1/logconf/session//logger/
/admin/v1/logconf/context//loggers/
/admin/v1/logconf/context//logger/
/admin/v1/logconf/context//user//loggers/
/admin/v1/logconf/context//user//logger/
/admin/v1/logconf/suppressed/exception-categories
/admin/v1/logconf/context//user//stacktrace/include-on-error

Configuration

SCR-1329

Summary: Added config option to avoid using IMAP entity's display name when listing shared folders

Effective: applies to the 8.35 release line

Added new lean config option com.openexchange.imap.useIMAPEntityDisplayNameIfPossible to control whether to use IMAP entity's display name when listing shared folders. Default is true

Packaging/Bundles

SCR-1293

Summary: New bundle com.openexchange.logging.rest

Effective: applies to the 8.35 release line

Introduced a new bundle com.openexchange.logging.rest, as part of the open-xchange-core package, which provides a RESTful API for configuring logging behavior.

8.20

General

SCR-1328

Summary: Removed CPU Resource Limit

Effective: applies to the 8.35 release line

Removed CPU resource limit since it's not best practice to have it set, see https://home.robusta.dev/blog/stop-using-cpu-limits

SCR-1227

Summary: Enhanced existent SOAP end-points by standard "Scheduled" folder

Effective: applies to the 8.35 release line

Enhanced existent SOAP end-points by standard "Scheduled" folder. The folder that holds such E-Mails that are scheduled for being sent at a later time.

To do so, the "User" data object contained in several SOAP end-points has been extended by "mail_folder_scheduled_full_name" element to output/specify the standard "Scheduled" folder.

3rd Party Libraries/License Change

SCR-1326

Summary: Updated Hazelcast from v3.5.1 to v3.5.6

Effective: applies to the 8.35 release line

Updated Hazelcast from v3.5.1 to v3.5.6 in bundle com.hazelcast

SCR-1325

Summary: Updated Google Guava from v32.1.1 to v32.1.3

Effective: applies to the 8.35 release line

Updated Google Guava from v32.1.1 to v32.1.3 in bundle com.google.guava

API - HTTP-API

SCR-1302

Summary: Added context_id field to TokenLogin json response

Effective: applies to the 8.35 release line

Added integer field context_id to tokenLogin JSON response, needed for successful request analyzing.

{
    "jsessionid": "<JSESSIONID>",
    "user":"<USER>",
    "user_id":10,
    "context_id":2,
    "url":"https://path/to/redirect"
} 

Behavioral Changes

SCR-1310

Summary: Enabled Redis-based session storage by default

Effective: applies to the 8.35 release line

Changed default value for properties

  • The already introduced Redis-based session storage is now enabled by default with this behavioral change. Precisely, the former added property "com.openexchange.sessiond.redis.enabled" is now assumed to be "true" if not specified otherwise.

  • Furthermore, the property "com.openexchange.sessionstorage.hazelcast.enabled" is now assumed to be "false" if not specified otherwise.

  • Please follow the instructions given at this article in order to set further config options for having the Middleware being orderly connected against running Redis backend.

Deprecation of former implementations

Moreover, the implementing classes for interface com.openexchange.sessiond.SessiondService and com.openexchange.sessionstorage.SessionStorageService are marked as deprecated. This applies to:

  • The in-memory based com.openexchange.sessiond.impl.SessiondServiceImpl as well as
  • The Hazelcast-backed com.openexchange.sessionstorage.hazelcast.HazelcastSessionStorageService

Configuration

SCR-1317

Summary: Added configuration options to enable debugging/profiling SQL queries

Effective: applies to the 8.35 release line

Added new lean configuration options to trace queries and their execution/fetch times

  • com.openexchange.database.profileSQL Enables to trace queries and their execution/fetch times. Default is false. Neither reloadable nor config-cascade aware.

  • com.openexchange.database.logger The name of a class that implements 'com.mysql.cj.log.Log' that will be used to log messages to. Default is 'com.mysql.cj.log.Slf4JLogger'. Neither reloadable nor config-cascade aware.

SCR-1316

Summary: New Default Value for "com.openexchange.tools.images.transformations.maxSize"

Effective: applies to the 8.35 release line

To better support practical use cases, the default value for the configuration property com.openexchange.tools.images.transformations.maxSize is adjusted from 10485760 (10 MB) to 20971520 (20 MB).

SCR-1309

Summary: Added lean property com.openexchange.database.logWritesToNonLocalSegments

Effective: applies to the 8.35 release line

Added lean property com.openexchange.database.logWritesToNonLocalSegments configuring whether to log writeable database accesses from non-local sites. Defaults to false

SCR-1284

Summary: Add parameters to drive jump redirect for request analyzing

Effective: applies to the 8.35 release line

Added context_id and user_id parameters to drive jump redirect url com.openexchange.drive.jumpLink

New default value is [protocol]://[hostname]/[uiwebpath]#[app]&[folder]&[id]&[context]&[user]

SCR-1211

Summary: Added several configuration options for scheduled mails

Effective: applies to the 8.35 release line

Added several lean configuration options for scheduled mails

  • com.openexchange.mail.scheduled.enabled Switch to enable or disable the scheduled mail feature. Default is true. Both - reloadable and config-cascade aware.

  • com.openexchange.mail.scheduled.maxNumberOfScheduledMails The max. allowed number of scheduled mails per user. Default is 1000. Both - reloadable and config-cascade aware.

  • com.openexchange.mail.scheduled.maxNumberOfScheduledMailsPerHour The max. allowed number of scheduled mails being sent per hour for a user. Default is 100. Both - reloadable and config-cascade aware.

  • com.openexchange.mail.scheduled.checkFrequencyMinutes The frequency in minutes when to check for due scheduled mails. Default is 30. Reloadable, but not config-cascade aware.

  • com.openexchange.mail.scheduled.lookAheadMinutes The look-ahead in minutes specifies the extra time added to current time when a scheduled mail is considered as due. Default is 35. Reloadable, but not config-cascade aware.

  • com.openexchange.mail.scheduled.lockExpiryMinutes The time in minutes when the lock marking a scheduled mail as "in processing" is considered as expired and thus may be newly acquired by another process. Default is 5. Reloadable, but not config-cascade aware.

  • com.openexchange.mail.scheduled.lockRefreshMinutes The time in minutes when the lock marking a scheduled mail as "in processing" is refreshed by lock-holding process. Default is 2. Reloadable, but not config-cascade aware.

Database

SCR-1225

Summary: Added new tables for scheduled mail feature

Effective: applies to the 8.35 release line

Added new tables in user database for scheduled mail feature

CREATE TABLE scheduledMail(
 uuid BINARY(16) NOT NULL,
 cid INT4 unsigned NOT NULL,
 user INT4 unsigned NOT NULL,
 dateToSend BIGINT(64) unsigned NOT NULL,
 mailPath TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
 processing BIGINT(64) unsigned NOT NULL DEFAULT 0,
 meta TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 PRIMARY KEY (uuid),
 KEY id (cid, user, uuid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

CREATE TABLE scheduledMailLock(
 cid INT4 unsigned NOT NULL DEFAULT 0,
 user INT4 unsigned NOT NULL DEFAULT 0,
 name VARCHAR(16) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
 stamp BIGINT(64) unsigned NOT NULL,
 PRIMARY KEY (cid, user, name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

Packaging/Bundles

SCR-1226

Summary: Added new bundles for scheduled mail feature

Effective: applies to the 8.35 release line

8.19

3rd Party Libraries/License Change

SCR-1308

Summary: Update vulnerable 3rd party libraries

Effective: applies to the 8.35 release line

Target platform: New libraries:

  • jackson-core-2.15.3.jar
  • jackson-annotations-2.15.3.jar
  • jackson-dataformat-xml-2.15.3.jar
  • jackson-databind-2.15.3.jar
  • jackson-dataformat-cbor-2.15.3.jar
  • jackson-dataformat-yaml-2.15.3.jar
  • jackson-datatype-jsr310-2.15.3.jar
  • jackson-datatype-jsr353-2.15.3.jar
  • jackson-jakarta-rs-base-2.15.3.jar
  • jackson-jakarta-rs-json-provider-2.15.3.jar
  • jackson-jakarta-rs-xml-provider-2.15.3.jar
  • jackson-module-jakarta-xmlbind-annotations-2.15.3.jar
  • jackson-module-jaxb-annotations-2.15.3.jar
  • jakarta.activation-api-2.1.2.jar
  • jakarta.json-api-2.1.2.jar
  • jackrabbit-webdav-2.21.19-custom.jar
  • snappy-java-1.1.10.3.jar
  • commons-fileupload-1.5.jar

Removed libraries:

  • jackson-core-2.14.2.jar
  • jackson-annotations-2.14.2.jar
  • jackson-dataformat-xml-2.14.2.jar
  • jackson-databind-2.14.2.jar
  • jackson-dataformat-cbor-2.14.2.jar
  • jackson-dataformat-yaml-2.14.2.jar
  • jackson-datatype-jsr310-2.14.2.jar
  • jackson-datatype-jsr353-2.14.2.jar
  • jackson-jakarta-rs-base-2.14.2.jar
  • jackson-jakarta-rs-json-provider-2.14.2.jar
  • jackson-jakarta-rs-xml-provider-2.14.2.jar
  • jackson-module-jakarta-xmlbind-annotations-2.14.2.jar
  • jackson-module-jaxb-annotations-2.14.2.jar
  • jakarta.activation-api-2.1.0.jar
  • jakarta.activation-2.0.1.jar
  • jackrabbit-webdav-2.19.1.jar
  • sqlite-jdbc-3.19.3.jar
  • commons-fileupload-1.4.jar

Bundle com.squareup.okhttp3: New libraries:

  • kotlin-stdlib-common-1.9.10.jar
  • kotlin-stdlib-1.9.10.jar
  • okio-jvm-3.5.0.jar
  • okio-3.5.0.jar
  • okhttp-4.11.0.jar
  • logging-interceptor-4.11.0.jar

Removed libraries:

  • kotlin-stdlib-common-1.7.22.jar
  • kotlin-stdlib-1.7.22.jar
  • okio-jvm-2.8.0.jar
  • okhttp-4.9.3.jar
  • logging-interceptor-4.9.3.jar

Bundle com.ctc.wstx: New library:

  • woodstox-core-6.5.1.jar

Removed library:

  • woodstox-core-6.5.0.jar

Bundle org.yaml.snakeyaml: New library:

  • snakeyaml-2.2.jar

Removed library:

  • snakeyaml-1.33.jar

Bundle com.nimbus: New libraries:

  • json-smart-2.4.11.jar
  • accessors-smart-2.4.11.jar

Removed libraries:

  • json-smart-2.4.8.jar
  • accessors-smart-2.4.8.jar

SCR-1266

Summary: Upgraded gson from 2.9.0 to 2.10.1

Effective: applies to the 8.35 release line

Upgraded the gson library from 2.9.0 to 2.10.1

API - HTTP-API

SCR-1304

Summary: Dropped shard query parameter from SAML request

Effective: applies to the 8.35 release line

Dropped shard query paramter from SAML request

Configuration

SCR-1307

Summary: New property to configure allowed URI schemes for external calendar attachments

Effective: applies to the 8.35 release line

In order to prevent inaccessible attachment references getting stored for appointments imported to App Suite, a new lean configuration property is introduced.

Its value can be configured to a comma-separated list of URI schemes that are allowed be stored for externally linked attachments of appointments. Attachments with other URI schemes will be rejected/ignored during import:

com.openexchange.calendar.allowedAttachmentSchemes=http,https,ftp,ftps

The property is reloadable, and can be defined through the config cascade sown to level "context".

SCR-1303

Summary: Dropped sharding related property

Effective: applies to the 8.35 release line

Dropped property com.openexchange.server.shardName

SCR-1277

Summary: New properties for Segmenter Client Service

Effective: applies to the 8.35 release line

For accessing a segmenter service in a sharded environment with multiple data centers ("Active/Active"), a new configuration property is introduced where the base URI to the service can be defined (empty by default):

com.openexchange.segmenter.baseUrl=

Also, a new configuration property is introduced through which the identifier of the 'local' site can be defined, defaulting to the value default.

com.openexchange.segmenter.localSiteId=default

Both properties are reloadable. By default, if no segmenter service URI is defined, a non-sharded environment is assumed where all segments are served by the local site itself.

Packaging/Bundles

SCR-1315

Summary: Deprecation of Kerberos Authentication

Effective: applies to the 8.35 release line

The Kerberos authentication integration that was available via supplementary package open-xchange-authentication-kerberos is now deprecated and subject for removal in a future release.

SCR-1312

Summary: Removed obsolete bundle com.openexchange.message.timeline

Effective: applies to the 8.35 release line

As it is no longer used, bundle com.openexchange.message.timeline is removed, along with its reference in open-xchange-core package.

SCR-1311

Summary: Removed obsolete Rhino Scripting

Effective: applies to the 8.35 release line

As they're no longer used, the following bundles are removed, along with their references in open-xchange-halo package:

  • com.openexchange.scripting.rhino
  • com.openexchange.scripting.rhino.apiBridge

SCR-1241

Summary: Added new bundles for the request analyzer feature

Effective: applies to the 8.35 release line

The following new bundles are added to open-xchange-core in order to support request routing in sharded environments with multiple data centers ("Active/Active"):

  • com.openexchange.request.analyzer
  • com.openexchange.request.analyzer.rest
  • com.openexchange.segmenter.client

8.18

3rd Party Libraries/License Change

SCR-1286

Summary: Updated lettuce library from v6.2.5 to v6.2.6

Effective: applies to the 8.35 release line

Updated lettuce library from v6.2.5 to v6.2.6 in bundle io.lettuce

SCR-1285

Summary: Updated Netty NIO libraries from v4.1.94 to v4.1.97

Effective: applies to the 8.35 release line

Updated Netty NIO libraries from v4.1.94 to v4.1.97 in bundle io.netty

API - HTTP-API

SCR-1300

Summary: Remove templating as valid format option

Effective: applies to the 8.35 release line

The publication and OXMF-based subscriptions features were removed with 7.10.2, see also MW-1089. Now, we remove a leftover within the API. The

&format=template

API parameter is no longer supported and will result in an error if used. 

SCR-1297

Summary: Deprecate transport "websocket" in "pns" API

Effective: applies to the 8.35 release line

To get rid of the stateful socket between Frontend and App Suite MW, Switchboard will be the only service that maintains a socket connection to clients. Instead of pushing directly from MW to the Client, MW will just use a HTTP webhook of Switchboard to announce new events. Switchboard will then push to the client.

Therefore the websocket transport identifier as used in actions subscribe and unsubscribe of the pns module in the HTTP API is now deprecated and will finally be removed in a future version.

Behavioral Changes

SCR-1272

Summary: Convert mail user flags to UTF-8

Effective: applies to the 8.35 release line

Mail user flags are persisted in UTF-7 on the mail server. However, web clients like the App Suite UI do use UTF-8 as default encoding for strings in communication with the Middleware.

Instead of using user flags as-is, the Middleware now converts incoming or outgoing user flags as need, so web clients can use UTF-8 based strings for mail user flags as usual.

Configuration

SCR-1301

Summary: Remove properties regarding user templating

Effective: applies to the 8.35 release line

With 7.10.2, we removed the publications and OXMF-based subscriptions features, see MW-1089. 

Now the last pieces of code belonging to those features were removed. Along the code, two properties that aren't needed anymore, have been removed:

com.openexchange.templating.trusted 
com.openexchange.templating.usertemplating

SCR-1278

Summary: Added configuration option to enable/disable encoding of IMAP user flags

Effective: applies to the 8.35 release line

Added configuration option controlling whether IMAP user flags are supposed to be encoded using RFC2060's UTF-7 encoding. Thus allowing non-ascii strings being stored as user flags.

Added support for properties:

  • "com.openexchange.imap.useUTF7ForUserFlags" Enables (or disables) whether IMAP user flags are supposed to be encoded/decoded using RFC2060's UTF-7 encoding. Default value is "false". Config-cascade aware.

  • "com.openexchange.imap.primary.useUTF7ForUserFlags" Enables (or disables) whether IMAP user flags are supposed to be encoded/decoded only for the primary IMAP account using RFC2060's UTF-7 encoding. Default value is "false". Config-cascade aware. This property effectively overwrites "com.openexchange.imap.encodeUserFlagsAsUTF7" for primary IMAP accounts

SCR-1229

Summary: Introduced new properties for Webhooks support

Effective: applies to the 8.35 release line

Introduced new lean properties for Webhooks support.

Webhook properties

  • com.openexchange.webhooks.enabledIds Specifies a comma-separated list of Webhook identifiers that are considered as enabled. Reloadable and config-cascade aware.

Webhook PNS properties

  • com.openexchange.pns.transport.webhooks.enabled Specifies whether the Webhook transport is enabled. Reloadable and config-cascade aware.

  • com.openexchange.pns.transport.webhooks.httpsOnly Whether only HTTPS is accepted when communicating with a Webhook. Reloadable and config-cascade aware.

  • com.openexchange.pns.transport.webhooks.allowTrustAll Whether SSL configuration for "trust all" is allowed. If set to "false" only valid certificates are accepted when communicating with a Webhook using a secure connection. Neither reloadable nor config-cascade aware.

  • com.openexchange.pns.transport.webhooks.allowLocalWebhooks Whether Webhooks having end-point set to an internal address are allowed. Neither reloadable nor config-cascade aware.

Webhook PNS HTTP properties

  • com.openexchange.pns.transport.webhooks.http.maxConnections The number of total connections held in HTTP connection pool for communicating with a certain Webhook end-point. Reloadable and config-cascade aware.

  • com.openexchange.pns.transport.webhooks.http.maxConnectionsPerHost The number of connections per route held in HTTP connection pool for communicating with a certain Webhook end-point. Reloadable and config-cascade aware.

  • com.openexchange.pns.transport.webhooks.http.connectionTimeout Specifies the timeout in milliseconds until a connection is established to a certain Webhook end-point. Reloadable and config-cascade aware.

  • com.openexchange.pns.transport.webhooks.http.socketReadTimeout Specifies the socket timeout in milliseconds, which is the timeout for waiting for data when communicating with a certain Webhook end-point.. Reloadable and config-cascade aware.

Webhook configuration file

Added new configuration file webhooks.yml containing the static configurations for known Webhook end-points. That file is in YAML notation and expects the following structure

 <unique-identifier>:
     uri: <URI>
       String. The URI end-point of the Webhook. May be overridden during subscribe depending on "uriValidationMode".

     uriValidationMode: <uri-validation-mode>
       String. Specifies how the possible client-specified URI for a Webhook end-point is supposed to be validated against the URI
               from configured Webhook end-point. Possible values: `none`, `prefix`, and `exact`. For `none` no requirements given.
               Any client-specified URI is accepted. For `prefix` he client-specified and configured URI for a Webhook end-point are
               required to start with same prefix. For `exact` the client-specified and configured URI for a Webhook end-point are
               required to be exactly the same. `prefix` is default.

     webhookSecret: <webhook-secret>
       String. The value for the "Authorization" HTTP header to pass on calling Webhook's URI. May be overridden during subscribe.

     login: <login>
       String. The login part for HTTP Basic Authentication if no value for the "Authorization" HTTP header is specified. May be overridden during subscribe.

     password: <password>
       String. The password part for HTTP Basic Authentication if no value for the "Authorization" HTTP header is specified. May be overridden during subscribe.

     signatureSecret: <signature-secret>
       String. Specifies shared secret known by caller and Webhook host. Used for signing.

     version: <version>
       Integer. Specifies the version of the Webhook. Used for signing.

     signatureHeaderName: <signature-header-name>
       String. Specifies the name of the signature header that carries the signature.

     maxTimeToLiveMillis: <max-time-to-live>
       Number. The max. time to live in milliseconds for the Webhook before considered as expired. If absent Webhook "lives" forever.

     maxNumberOfSubscriptionsPerUser: <max-number-per-user>
       Number. The max. number of subscriptions for this Webhook allowed for a single user. Equal or less than 0 (zero) means infinite.

     allowSharedUri: <allow-shared-uri>
       Boolean. Whether the same URI can be used by multiple different users or not. Optional, defaults to `true`.


Example

webhooks.yml

mywebhook:
    uri: https://my.endpoint.com:8080/webhook/event
    webhookSecret: supersecret
    signatureSecret: da39a3ee5e6b4b
    version: 1
    signatureHeaderName: X-OX-Signature
    maxTimeToLiveMillis: 2678400000
    maxNumberOfSubscriptionsPerUser: 2
    uriValidationMode: prefix

Database

SCR-1296

Summary: Changed column 'propertyValue' of table 'subadmin_config_properties' to be of type TEXT

Effective: applies to the 8.35 release line

Modified Config-DB to have column 'propertyValue' of table 'subadmin_config_properties' to be of type TEXT

New table layout is therefore:

CREATE TABLE subadmin_config_properties (
    sid INT4 UNSIGNED NOT NULL,
    propertyKey VARCHAR(64) CHARACTER SET latin1 NOT NULL DEFAULT '',
    propertyValue TEXT CHARACTER SET latin1 NOT NULL DEFAULT '',
    PRIMARY KEY (sid, propertyKey)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci;

This database change contains no update task since this is a modification of the Config-DB, which is performed through liquibase framework on node start-up

SCR-1258

Summary: Added column meta to table pns_subscription

Effective: applies to the 8.35 release line

Update Task com.openexchange.pns.subscription.storage.groupware.PnsSubscriptionsAddMetaColumTask

Added TEXT column meta to table pns_subscription:

meta TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL

Packaging/Bundles

SCR-1294

Summary: Added new bundle for Config-Cascade implementation

Effective: applies to the 8.35 release line

Added new bundle com.openexchange.config.cascade.impl containing Config-Cascade implementation. This separates the API classes from actual implementation and allows less dependencies. That new bundle is added to open-xchange-core package

SCR-1228

Summary: New bundles for Webhooks support

Effective: applies to the 8.35 release line

Introduced new bundles for Webhooks support

  • com.openexchange.webhooks
  • com.openexchange.pns.transport.webhooks

8.17

3rd Party Libraries/License Change

SCR-1275

Summary: Upgraded MySQL Connector for Java

Effective: applies to the 8.35 release line

Upgraded MySQL Connector for Java from v8.0.29 to v8.0.33 in OSGi target platform

SCR-1270

Summary: Updated Google Client API libraries

Effective: applies to the 8.35 release line

Updated Google Client API libraries

  • google-api-client-1.35.1.jar to google-api-client-2.2.0.jar
  • google-api-client-appengine-1.35.1.jar to google-api-client-appengine-2.2.0.jar
  • google-api-client-gson-1.35.1.jar to google-api-client-gson-2.2.0.jar
  • google-api-client-jackson2-1.35.1.jar to google-api-client-jackson2-2.2.0.jar
  • google-api-client-protobuf-1.35.1.jar to google-api-client-protobuf-2.2.0.jar
  • google-api-client-servlet-1.35.1.jar to google-api-client-servlet-2.2.0.jar
  • google-api-client-xml-1.35.1.jar to google-api-client-xml-2.2.0.jar

  • google-api-services-calendar-v3-rev20220520-1.32.1.jar to google-api-services-calendar-v3-rev20230602-2.0.0.jar

  • google-api-services-drive-v3-rev20220508-1.32.1.jar to google-api-services-drive-v3-rev20230610-2.0.0.jar

  • google-api-services-gmail-v1-rev20220404-1.32.1.jar to google-api-services-gmail-v1-rev20230612-2.0.0.jar

  • google-api-services-oauth2-v2-rev20200213-1.32.1.jar to google-api-services-oauth2-v2-rev20200213-2.0.0.jar

  • google-api-services-people-v1-rev20220531-1.32.1.jar to google-api-services-people-v1-rev20230103-2.0.0.jar

API - HTTP-API

SCR-1232

Summary: Extended updateAttendee call with tranps parameter

Effective: applies to the 8.35 release line

To allow per-attendee transparency for a certain event, the HTTP API call updateAttedee was extended by the optional parameter transp. Allowed values for the new parameter are:

TRANSPARENT
OPAQUE

If the transparency is set for a certain attendee, the event transparency for the corresponding event is adjusted implicitly, including all other chronos related calls.

Database

SCR-1264

Summary: Update task to insert missing references into 'filestore2user' table

Effective: applies to the 8.35 release line

Update Task com.openexchange.groupware.update.tasks.Filestore2UserUpdateReferencesTask

To ensure the table filestore2user (in config-db) holds all references to users with individual filestores in a groupware schema , a new update task named com.openexchange.groupware.update.tasks.Filestore2UserUpdateReferencesTask is introduced.

API - SOAP

SCR-1280

Summary: Added possibility to manage user sessions through SOAP interface

Effective: applies to the 8.35 release line

Added the possibility to manage user sessions through the new OXSessionService SOAP interface

Packaging/Bundles

SCR-1281

Summary: Added new bundle/package to manage sessions via SOAP

Effective: applies to the 8.35 release line

Added new bundle com.openexchange.sessiond.soap to manage sessions via SOAP. That new bundle is contained in newly introduced package open-xchange-sessiond-soap

8.16

General

SCR-1252

Summary: Updated Netty NIO libraries

Effective: applies to the 8.35 release line

Updated Netty NIO libraries from v4.1.89 to v4.1.94 in bundle io.netty

3rd Party Libraries/License Change

SCR-1256

Summary: Upgraded Javassist Library

Effective: applies to the 8.35 release line

Library Javasisst is upgraded to v3.29.2-GA in target platform com.openexchange.bundles and bundle com.openexchange.test.

SCR-1255

Summary: Updated Apache Tika library

Effective: applies to the 8.35 release line

Updated Apache Tika library from v2.6.0 to v2.8.0 in bundle com.openexchange.tika.util

SCR-1253

Summary: Updated lettuce library

Effective: applies to the 8.35 release line

Updated lettuce library from v6.2.3 to v6.2.5 in bundle io.lettuce

SCR-1247

Summary: Updated pushy library from v0.15.1 to v0.15.2

Effective: applies to the 8.35 release line

Updated pushy library from v0.15.1 to v0.15.2 in bundle com.eatthepath.pushy

SCR-1245

Summary: Updated metadata-extractor from v2.17.0 to v2.18.0

Effective: applies to the 8.35 release line

Updated 3rd party library metadata-extractor from v2.17.0 to v2.18.0 in bundle com.drew

SCR-1244

Summary: Updated htmlcleaner from v2.22 to v2.29

Effective: applies to the 8.35 release line

Updated 3rd party library htmlcleaner from v2.22 to v2.29 in target platform

SCR-1243

Summary: Updated dnsjava from v3.5.1 to v3.5.2

Effective: applies to the 8.35 release line

Updated 3rd party library dnsjava from v3.5.1 to v3.5.2 in target platform

SCR-1242

Summary: Updated Apache HttpCore and HttpClient libraries

Effective: applies to the 8.35 release line

Updated Apache HttpCore and HttpClient libraries

  • Updated HttpCore from v4.4.15 to v4.4.16
  • Updated HttpClient from v4.5.13 to v4.5.14

SCR-1234

Summary: Updated Hazelcast Core Module

Effective: applies to the 8.35 release line

Updated Hazelcast Core Module from v5.2.1 to v5.3.1

SCR-1231

Summary: Updated OSGi target platform bundles

Effective: applies to the 8.35 release line

Updated OSGi target platform bundles

  • org.eclipse.osgi.services_3.10.200.v20210723-0643.jar updated to org.eclipse.osgi.services_3.11.100.v20221006-1531.jar
  • org.eclipse.osgi.util_3.6.100.v20210723-1119.jar updated to org.eclipse.osgi.util_3.7.200.v20230103-1101.jar
  • org.eclipse.osgi_3.18.0.v20220516-2155.jar updated to org.eclipse.osgi_3.18.400.v20230509-2241.jar

Added new OSGi bundles to target platform

Since content of shipped org.eclipse.osgi.services bundle has been changed. Missing classes/interfaces are now contained in separate OSGi bundles.

  • Added org.osgi.annotation.bundle_2.0.0.202202082230.jar
  • Added org.osgi.annotation.versioning_1.1.2.202109301733.jar
  • Added org.osgi.service.cm_1.6.1.202109301733.jar
  • Added org.osgi.service.component_1.5.1.202212101352.jar
  • Added org.osgi.service.component.annotations_1.5.1.202212101352.jar
  • Added org.osgi.service.device_1.1.1.202109301733.jar
  • Added org.osgi.service.event_1.4.1.202109301733.jar
  • Added org.osgi.service.metatype_1.4.1.202109301733.jar
  • Added org.osgi.service.metatype.annotations_1.4.1.202109301733.jar
  • Added org.osgi.service.prefs_1.1.2.202109301733.jar
  • Added org.osgi.service.provisioning_1.2.0.201505202024.jar
  • Added org.osgi.service.repository_1.1.0.201505202024.jar
  • Added org.osgi.service.upnp_1.2.1.202109301733.jar
  • Added org.osgi.service.useradmin_1.1.1.202109301733.jar
  • Added org.osgi.service.wireadmin_1.0.2.202109301733.jar
  • Added org.osgi.util.function_1.2.0.202109301733.jar
  • Added org.osgi.util.measurement_1.0.2.201802012109.jar
  • Added org.osgi.util.position_1.0.1.201505202026.jar
  • Added org.osgi.util.promise_1.3.0.202212101352.jar
  • Added org.osgi.util.xml_1.0.2.202109301733.jar

API - HTTP-API

SCR-1235

Summary: Introduced a new action to the 'mail' module for exporting mails as PDFs

Effective: applies to the 8.35 release line

Introduced the action export_PDF to the mail module.

It is a PUT request and has the following URL parameters:

  • folder: defines the mail folder which holds the mail that shall be exported
  • id: defines the mail id

The request also accepts a mandatory JSON body with the following attributes:

  • folder_id: Defines the drive folder in which the exported PDF/A document will be saved. This option is required.
  • pageFormat: Defines the page format of the export document. It can either be a4 (which is the default behaviour) or letter. This option is not required. If absent, the page format will be derived from the user's locale setting (for us or ca the page format will be letter and for anything else a4).
  • preferRichText: If this option is enabled then, if an e-mail message contains both text and HTML versions of the body, then the latter is preferred and converted to a PDF/A document before it is appended to the exported PDF/A document. If only the text version is available, and the option is enabled, then the text version is converted to a PDF/A document and appended to the exported PDF/A document. This option is not required and by default is set to true.
  • includeExternalImages: If this option is enabled then, and the e-mail contains any external inline images, then those images will be fetched from their respective sources and included to the exported PDF/A document at their supposed positions. This option is not required and is by default false.
  • appendAttachmentPreviews: If this option is enabled, then any previewable attachment (i.e., documents and pictures) is converted from their original format, e.g., from docx or tiff, to a PDF/A document and is appended as one or more pages to the exported PDF/A document. This option is not required and is false by default.
  • embedAttachmentPreviews: If this option is enabled, then any previewable attachment is converted from their original format to a PDF/A document and is embedded as an attachment to the exported PDF/A document. This option is not required and is false by default.
  • embedRawAttachments: If this option is enabled, then all attachments are embedded without further processing to the exported PDF/A document as attachments. This option is not required and is false by default.
  • embedNonConvertibleAttachments: If this option is enabled, then all attachments (previewable and non-previewable, i.e., zips, mp4s, etc.) are embedded without further processing to the exported PDF/A document as attachments. This option is not required and is false by default.

Configuration

SCR-1240

Summary: Introduced a new capability to activate the PDF MailExportService

Effective: applies to the 8.35 release line

Introduced the capability mail_export_pdf to activate the PDF MailExportService.

SCR-1239

Summary: Introduced new properties for the CollaboraPDFAConverter

Effective: applies to the 8.35 release line

Introduced the following properties to configure the `CollaboraPDFAConverter`:

  • com.openexchange.mail.exportpdf.pdfa.collabora.enabled: Defines whether the collabora online converter is enabled. Defaults to false
  • com.openexchange.mail.exportpdf.pdfa.collabora.url: The Collabora URL to use: Allows to specify a dedicated Collabora service only for PDFA creation. By default is empty and uses the server configured via the property `com.openexchange.mail.exportpdf.collabora.url`.

SCR-1238

Summary: Introduced new properties for the GotenbergMailExportConverter

Effective: applies to the 8.35 release line

Introduced the following properties to configure the GotenbergMailExportConverter:

  • com.openexchange.mail.exportpdf.gotenberg.enabled: Defines whether the gotenberg online converter is enabled. Defaults to false
  • com.openexchange.mail.exportpdf.gotenberg.url: Defines the base URL of the Gotenberg Online server. Defaults to http://localhost:3000
  • com.openexchange.mail.exportpdf.gotenberg.fileExtensions: Defines a comma separated list of file extensions that are handled by the gotenberg converter. Defaults to htm, html.
  • com.openexchange.mail.exportpdf.gotenberg.pdfFormat: Specifies which PDF format to use. "PDF/A-1a", "PDF/A-2b" and "PDF/A-3b" are supported formats, or "PDF" for regular PDF. Defaults to "PDF"

SCR-1237

Summary: Introduced new properties for the CollaboraMailExportConverter

Effective: applies to the 8.35 release line

Introduced the following properties to configure the CollaboraMailExportConverter:

  • com.openexchange.mail.exportpdf.collabora.enabled: Defines whether the collabora online converter is enabled. Defaults to false
  • com.openexchange.mail.exportpdf.collabora.url: Defines the base URL of the Collabora Online server. Defaults to http://localhost:9980
  • com.openexchange.mail.exportpdf.collabora.fileExtensions: Defines a comma separated list of file extensions that are handled by the collabora converter. Defaults to sxw, odt, fodt, sxc, ods, fods, sxi, odp, fodp, sxd, odg, fodg, odc, sxg, odm, stw, ott, otm, stc, ots, sti, otp std, otg, odb, oxt, doc, dot xls, ppt, docx, docm, dotx, dotm, xltx, xltm, xlsx, xlsb, xlsm, pptx, pptm, potx, potm, wpd, pdb, hwp, wps, wri, wk1, cgm, dxf, emf, wmf, cdr, vsd, pub, vss, lrf, gnumeric, mw, numbers, p65, pdf, jpg, jpeg, gif, png, dif, slk, csv, dbf, oth, rtf, txt, html, htm, xml.
  • com.openexchange.mail.exportpdf.collabora.imageReplacementMode: Defines the mode on how to handle/replace inline images. Defaults to distributedFile.

SCR-1236

Summary: Introduced new properties for the MailExportService

Effective: applies to the 8.35 release line

Introduced the following properties to configure the MailExportService:

  • com.openexchange.mail.exportpdf.concurrentExports: Defines the maximum concurrent mail exports that the server is allowed to process. If the limit is reached an error will be returned to the client, advising it to retry again in a while. Defaults to 10. 
  • com.openexchange.mail.exportpdf.pageMarginTop: Defines the top margin (in millimeters) of the exported pages. Defaults to 12.7 millimeters (0.5 inches).
  • com.openexchange.mail.exportpdf.pageMarginBottom: Defines the bottom margin (in millimeters) of the exported pages. Defaults to 12.7 millimeters (0.5 inches).
  • com.openexchange.mail.exportpdf.pageMarginLeft: Defines the left margin (in millimeters) of the exported pages. Defaults to 12.7 millimeters (0.5 inches).
  • com.openexchange.mail.exportpdf.pageMarginRight: Defines the right margin (in millimeters) of the exported pages. Defaults to 12.7 millimeters (0.5 inches).
  • com.openexchange.mail.exportpdf.headerFontSize: Defines the font size of the exported mail's headers. Defaults to 12 points.
  • com.openexchange.mail.exportpdf.bodyFontSize: Defines the font size of the exported mail's body. Defaults to 12 points.
  • com.openexchange.mail.exportpdf.autoPageOrientation: Defines whether PDF pages will be auto-oriented in landscape mode whenever a full page appended image is in landscape mode. Defaults to false

Database

SCR-1233

Summary: Update encryption for passwords of anonymous guest users

Effective: applies to the 8.35 release line

Update Task com.openexchange.groupware.update.tasks.RecryptGuestUserPasswords

Update encryption for anonymous guest user passwords using newly introduced mechanisms with implicit salt

Table user altered, extend column userPassword from VARCHAR(128) to VARCHAR(512)

8.15

General

SCR-1227

Summary: Enhanced existent SOAP end-points by standard "Scheduled" folder

Effective: applies to the 8.35 release line

Enhanced existent SOAP end-points by standard "Scheduled" folder. The folder that holds such E-Mails that are scheduled for being sent at a later time.

To do so, the "User" data object contained in several SOAP end-points has been extended by "mail_folder_scheduled_full_name" element to output/specify the standard "Scheduled" folder.

SCR-1201

Summary: Added separate bundle offering HTTP liveness end-point

Effective: applies to the 8.35 release line

Added separate bundle com.openexchange.http.liveness part of open-xchange-core package list that offers the HTTP liveness end-point at configured HTTP host name (default "127.0.0.1") and liveness port (default 8016).

Configuration

SCR-1224

Summary: Add property com.openexchange.log.extensionHttpHeaders

Effective: applies to the 8.35 release line

com.openexchange.log.extensionHttpHeaders defines a comma separated list of HTTP headers that shall additionally be logged for incoming requests

Example com.openexchange.log.extensionHttpHeaders=X-custom-Header,X-host

The property is neither reloadable nor ConfigCascade-aware.

Database

SCR-1225

Summary: Added new tables for scheduled mail feature

Effective: applies to the 8.35 release line

Added new tables in user database for scheduled mail feature


CREATE TABLE scheduledMail(
 uuid BINARY(16) NOT NULL,
 cid INT4 unsigned NOT NULL,
 user INT4 unsigned NOT NULL,
 dateToSend BIGINT(64) unsigned NOT NULL,
 mailPath TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
 processing BIGINT(64) unsigned NOT NULL DEFAULT 0,
 meta TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 PRIMARY KEY (uuid),
 KEY id (cid, user, uuid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci


CREATE TABLE scheduledMailLock(
 cid INT4 unsigned NOT NULL DEFAULT 0,
 user INT4 unsigned NOT NULL DEFAULT 0,
 name VARCHAR(16) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
 stamp BIGINT(64) unsigned NOT NULL,
 PRIMARY KEY (cid, user, name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

SCR-1223

Summary: Update task to add the "claim" column to "calendar_alarm_trigger" table

Effective: applies to the 8.35 release line

Update Task com.openexchange.chronos.storage.rdb.groupware.CalendarAlarmTriggerAddClaimColumnTask

Adds the "claim" column to "calendar_alarm_trigger" table

8.14

3rd Party Libraries/License Change

SCR-1219

Summary: Upgraded JSoup library

Effective: applies to the 8.35 release line

Upgraded JSoup library in target platform (con.openexchange.bundles) from v1.15.3 to v1.16.1

API - HTTP-API

SCR-1216

Summary: Accept parameter harddelete for composition space's delete end-point

Effective: applies to the 8.35 release line

Accept boolean parameter "harddelete" for composition space's delete end-point

DELETE /mailcompose/draft.xyz?harddelete=true

If set to "true" any associated draft message for the denoted composition space gets hard-deleted. That is no copy is created in standard trash folder.

SCR-1213

Summary: New Flag all_others_declined for Events

Effective: applies to the 8.35 release line

The "flags" enumeration for events in chronos module of the HTTP API is extended by the value all_others_declined. If set, all other individual attendees in the event have a participation status of declined, which could be used by clients to show a hint that one might be alone in a meeting.

See [https://documentation.open-xchange.com/latest/middleware/calendar/implementation_details.html#event-flags] for further details.

SCR-1198

Summary: New Settings for Free/Busy Visibility in JSlob

Effective: applies to the 8.35 release line

The io.ox/calendar JSlob entry is extended by the following item which indicates the free/busy visibility of the user:

{
  "id": "io.ox/calendar",
  "tree": {
    "chronos": {
      "freeBusyVisibility": "all",
    }
  },
  "meta": {
    "chronos": {
      "freeBusyVisibility": {
        "possibleValues": [
          "all",
          "internal-only",
          "none"
        ],
        "configurable": true
      }
    }
  }
}

Within the meta section, clients are able to derive the possible values - the enumeration will only yield the value internal-only if cross-context features are available. Also, the "configurable" flag will indicate whether the property is settable by the user or not.

Configuration

SCR-1220

Summary: Introduce new properties for DAV client matching

Effective: applies to the 8.35 release line

Once in a while, vendors like Apple decide to change the User Agents of their products in a way, we don't recognize the matching clients anymore. Thus, the Open Xchange server isn't able to apply special handling for those clients. This leads to subsequent problems and errors.

Until 8.14, the user agent matching was a static, programmatically pre-defined process. For every user agent's change, there needed to be a patch applied. Now, the mechanism is replaced by a more dynamically approach:

Administrators can define regular expressions for the known *DAV clients. In detail, the following properties are added for known *DAV clients:

com.openexchange.dav.useragent.mac_calendar
com.openexchange.dav.useragent.mac_contacts
com.openexchange.dav.useragent.ios
com.openexchange.dav.useragent.ios_reminders
com.openexchange.dav.useragent.thunderbird_lightning
com.openexchange.dav.useragent.thunderbird_cardbook
com.openexchange.dav.useragent.em_client
com.openexchange.dav.useragent.ox_sync
com.openexchange.dav.useragent.caldav_sync
com.openexchange.dav.useragent.carddav_sync
com.openexchange.dav.useragent.smooth_sync
com.openexchange.dav.useragent.davdroid
com.openexchange.dav.useragent.davx5
com.openexchange.dav.useragent.outlook_caldav_synchronizer
com.openexchange.dav.useragent.windows_phone
com.openexchange.dav.useragent.windwos

All properties have pre-defined default values and are reloadable.

SCR-1218

Summary: New config option for sanitizing CSV cell content on contact export

Effective: applies to the 8.35 release line

New lean config option "com.openexchange.export.csv.sanitize" for sanitizing CSV cell content on contact export. Default is false. Reloadable, but not config-cascade aware

SCR-1217

Summary: New property to limit number of considered filestore candidates

Effective: applies to the 8.35 release line

New lean property com.openexchange.admin.limitFilestoreCandidates to limit number of considered filestore candidates to a reasonable amount when determining the filestore to use for a new context/user. Neither reloadable, nor config-cascade aware. Default is 100.

SCR-1215

Summary: Accept specifying a max. running time that must not be exceeded by execution of an individual health check

Effective: applies to the 8.35 release line

Accept new lean property for specifying a max. running time that must not be exceeded by execution of an individual health check

  • com.openexchange.health.maxRunningTimeSeconds The max. allowed running time in seconds for an individual health check. It a check's execution is canceled if it exceeds that running time. A value of equal to or less than zero 0 (zero) ignores this setting. Default is 5. Reloadbale, but not config-cascade aware.

SCR-1197

Summary: New Properties for Free/Busy Visibility

Effective: applies to the 8.35 release line

In order to define the default free/busy visibility setting of users, and to control whether it is changeable by end users, the following new lean configuration properties are introduced:

  • com.openexchange.calendar.freeBusyVisibility.default=all: Defines the default free/busy visibility setting to assume unless overridden by the user. Possible values are:
    • none to not expose a user's availability to others at all
    • internal-only to make the free/busy data available to other users within the same context
    • all to expose availability data also beyond context boundaries (i.e. for cross-context- or other external access if configured)
  • com.openexchange.calendar.freeBusyVisibility.protected=false: Configures if the default value that determines if public calendar folders from the default account are considered for synchronization may be overridden by the user or not.

More details are available at [https://documentation.open-xchange.com/components/middleware/config/latest/#mode=search&term=com.openexchange.calendar.freeBusyVisibility] .

8.13

General

SCR-1201

Summary: Added separate bundle offering HTTP liveness end-point

Effective: applies to the 8.35 release line

Added separate bundle com.openexchange.http.liveness part of open-xchange-core package list that offers the HTTP liveness end-point at configured HTTP host name (default "127.0.0.1") and liveness port (default 8016).

API - HTTP-API

SCR-1183

Summary: Deprecate delivery=view and content_disposition=inline options in HTTP API

Effective: applies to the 8.35 release line

The parameter options delivery=view and content_disposition=inline and the possibility to let the client define the content type of documents and attachments, can be used to inject executable scripts into data that is rendered in browsers. This lead to several bugs in the past. Therefore the usage of those options is deprecated and will be removed.

API - RMI

SCR-1207

Summary: Additional parameter 'auth' for data modification RMI services.

Effective: applies to the 8.35 release line

The following registered RMI services now require auth parameters for data modification interfaces. The parameter com.openexchange.auth.Credentials auth needs to be provided.

DBMigrationRMIService
OXContextGroup
RemoteAdvertisementService
ExternalAccountRMIService
RemoteCompositionSpaceService
SocketLoggerRMIService
LoginCounterRMIService
GABRestorerRMIService
SessiondRMIService
ChronosRMIService
ContactStorageRMIService
DataExportRMIService
ConsistencyRMIService
ContextRMIService
FileChecksumsRMIService
ResourceCacheRMIService
ShareRMIService
PushRMIService
UpdateTaskRMIService
LogbackConfigurationRMIService -> java.lang.String user, java.lang.String password

Behavioral Changes

SCR-1208

Summary: Deprecation of Internal OAuth Authorization Server

Effective: applies to the 8.35 release line

Certain APIs of the App Suite middleware can be accessed via OAuth 2.0. In this scenario, the middleware typically acts as resource server only, and the whole client- / grant management is done by an external IDM acting as authorization server. See [the documentation|https://documentation.open-xchange.com/latest/middleware/login_and_sessions/oauth_2.0_provider/01_operator_guide.html] for further details.

Mainly as demo/showcase, it has also been possible to configure the middleware to act as OAuth authorization server itself, with integrated client- and grant management. Since this never was or meant to be used in production, this part of the OAuth provider is now deprecated, and will be removed in an upcoming version.

In practical terms, this means that the setting auth_server for [com.openexchange.oauth.provider.mode|https://documentation.open-xchange.com/components/middleware/config/latest/#mode=search&term=com.openexchange.oauth.provider.mode] will no longer be available, along with dependent features and functionality.

Configuration

SCR-1203

Summary: New property com.openexchange.share.guestEmailCheckRegex

Effective: applies to the 8.35 release line

In order to prevent creation of guest users with certain email addresses, a new lean configuration property com.openexchange.share.guestEmailCheckRegex is introduced. The property is empty by default, reloadable and config-cascade aware.

It allows the definition of a regular expression pattern for email addresses of invited guest users. If defined, the email address of newly invited named guest users must additionally match the pattern (besides regular RFC 822 syntax checks, which are always performed), otherwise creation of the guest user is denied. The pattern is used in a case-insensitive manner.

This may be used to prevent specific email address domains for guests, e.g. by defining a pattern like

^((?!(?:@example\.com\s*$)|(?:@example\.org\s*$)).)*$

See https://documentation.open-xchange.com/components/middleware/config/latest/#mode=search&term=com.openexchange.share.guestEmailCheckRegex for further details.

SCR-1191

Summary: New property to control format of internal scheduling mails

Effective: applies to the 8.35 release line

In order to control whether scheduling-related notification mails to other internal entities are sent as regular iMIP message (including iCalendar attachment) or not, a new lean configuration property named com.openexchange.calendar.useIMipForInternalUsers is introduced. It defaults to false, is reloadable, and can be set through the config-cascade down to "context" level.

Since automatic scheduling takes place within a context, attendee and organizer copies of appointments are in sync implicitly, and updates don't need to be distributed via iMIP. However, still enabling iMIP mails (in favor of notification messages only) also for internal users may be useful if external client applications are in use, or to ease forwarding invitations to others.

SCR-1158

Summary: Disable mail push implementations by default, made existing properties reloadable

Effective: applies to the 8.35 release line

Changed default value for enabled properties for mail push features to false: * com.openexchange.push.dovecot.enabled * com.openexchange.push.imapidle.enabled * com.openexchange.push.mail.notify.enabled * com.openexchange.push.malpoll.enabled

Refactored mail push configuration, now all existing mail push related properties are lean and reloadable: * com.openexchange.push.dovecot.* * com.openexchange.push.imapidle.* * com.openexchange.push.mail.notify.* * com.openexchange.push.malpoll.*

Database

SCR-1186

Summary: New column uuid for table server in Config-DB

Effective: applies to the 8.35 release line

Update Task 8.12:server:addUuidColumn / com.openexchange.database.internal.change.custom.ServerAddUuidColumnCustomTaskChange

The table server in the config database will get extended by a new column named uuid with the following column definition:

`uuid` BINARY(16) NOT NULL

This will happen through the Liquibase change set with id "8.12:server:addUuidColumn", using the custom change implemented in class com.openexchange.database.internal.change.custom.ServerAddUuidColumnCustomTaskChange.

8.12

General

SCR-1195

Summary: New default value for com.openexchange.sessiond.maxSession property

Effective: applies to the 8.35 release line

With introduction of Redis-backed session storage the property com.openexchange.sessiond.maxSession specifying the max. allowed number of sessions becomes obsolete. That pretty old property's intention is to avoid memory problems on Middleware nodes hosting sessions node-local in memory. That is no more the case with Redis.

Hence, the old default value of "50000" for that property is changed to "0" (unlimited) in file /opt/open-xchange/etc/sessiond.properties.

API - HTTP-API

SCR-1200

Summary: Extended the mailfilter?action=config response to include blocked action commands for the apply action

Effective: applies to the 8.35 release line

To allow a client to disable the apply button for filter rules with blocked action commands, the response of the action=config call has been extended so that the options object now contains a 'blockedApplyActions' field which contains a string array of all the blocked actions.

Configuration

SCR-1199

Summary: Introduced the new lean property 'com.openexchange.mail.filter.options.apply.blockedActions' which allows to block certain mail filter actions from the apply action

Effective: applies to the 8.35 release line

Introduced the new lean property 'com.openexchange.mail.filter.options.apply.blockedActions' which defaults to "redirect". This property accepts a comma separated lists of mail filter actions which will be denied from the apply mail filter action. This helps, for example, to prevent that a message delivery system is overwhelmed by a lot of simultanous redirect actions.

SCR-1120

Summary: Allow enforcing 'STARTTLS' for IMAP, POP3, SMTP, sieve

Effective: applies to the 8.35 release line

Added a few lean properties to enforce usage of STARTTLS.

IMAP related properties: com.openexchange.imap.requireTls com.openexchange.imap.primary.requireTls

POP3 related properties com.openexchange.pop3.requireTls

SMTP related properties: com.openexchange.smtp.requireTls com.openexchange.smtp.primary.requireTls

Sieve related properties: com.openexchange.mail.filter.requireTls

All properties are reloadable and config-cascade aware. All properties default to true

8.11

API - Java

SCR-1145

Summary: Refactored CardDAV to use IDBasedContactsAccess

Effective: applies to the 8.35 release line

Interfaces changed due to refactoring CardDAV to use IDBasedContactsAccess

Added methods in com.openexchange.contact.provider.composition.IDBasedContactsAccess: Map<String, UpdatesResult<Contact>> getUpdatedContacts(List<String>, Date) - Gets lists of new and updated as well as deleted contacts since a specific timestamp in certain folders Map<String, SequenceResult> getSequenceNumbers(List<String>) - Gets the sequence numbers of certain contacts folders, which is the highest timestamp of all contained items String getCTag(String) - Retrieves the CTag (Collection Entity Tag) for a folder

Added methods in com.openexchange.contact.provider.folder.FolderSyncAware: Map<String, UpdatesResult<Contact>> getUpdatedContacts(List<String>, Date) - Gets lists of new and updated as well as deleted contacts since a specific timestamp in certain folders Map<String, SequenceResult> getSequenceNumbers(List<String>) - Gets the sequence numbers of certain contacts folders, which is the highest timestamp of all contained items

Behavioral Changes

SCR-1146

Summary: External contacts providers are now synced via CardDAV

Effective: applies to the 8.35 release line

External contacts providers are now synced via CardDAV after refactoring to use IDBasedContactsAccess

Configuration

SCR-1193

Summary: New Property "com.openexchange.admin.autoDeleteGuestsUsingFilestore"

Effective: applies to the 8.35 release line

In case a per-user filestore is associated to a guest user, and the "parent" user owning this filestore is deleted, the guest account is purged implicitly as well by default. In order to prevent that, a new lean, reloadable and config-cascade-aware property is introduced: com.openexchange.admin.autoDeleteGuestsUsingFilestore.

See https://documentation.open-xchange.com/components/middleware/config/latest/#mode=search&term=com.openexchange.admin.autoDeleteGuestsUsingFilestore for further details.

SCR-1190

Summary: Specify a timeout when reading responses from IMAP server after a command has been issued

Effective: applies to the 8.35 release line

Added new lean property "com.openexchange.imap.readResponsesTimeout" accepting to define a timeout in milliseconds when reading responses from IMAP server after a command has been issued. That timeout does only apply to subscribed (not provisioned) IMAP accounts; neither primary nor secondary ones.

Default value is 60000 (one minute). A value equal to zero is infinite timeout. Reloadable and config-cascade aware.

SCR-1189

Summary: Option to enable/disable usage of XCLIENT sieve extension

Effective: applies to the 8.35 release line

Added new lean configuration option "com.openexchange.mail.filter.allowXCLIENT" to explicitly enable (or disable) usage of the XCLIENT sieve extension. When a sieve server announces support for the XCLIENT command, a sieve client may send information that overrides one or more client-related session attributes.

Default is false (not enabled). Reloadable and config-cascade aware.

SCR-1188

Summary: Introduced a new lean property which allows to omit certain labels

Effective: applies to the 8.35 release line

Introduced the new lean property: com.openexchange.http.metrics.label.filter which allows to omit certain labels from http api metrics.

Packaging/Bundles

SCR-1184

Summary: Removed com.openexchange.hazelcast.upgrade* bundles

Effective: applies to the 8.35 release line

The following upgrade bundles are no longer needed in cloud environments after we introduced the new pre-upgrade framework (MW-1785): * com.openexchange.hazelcast.upgrade324 * com.openexchange.hazelcast.upgrade312 * com.openexchange.hazelcast.upgrade355 * com.openexchange.hazelcast.upgrade371 * com.openexchange.hazelcast.upgrade311 * com.openexchange.hazelcast.upgrade381 * com.openexchange.hazelcast.upgrade411 * com.openexchange.hazelcast.upgrade3100

Corresponding package definitions have been removed as well: * open-xchange-cluster-upgrade-from-76x * open-xchange-cluster-upgrade-from-780-782 * open-xchange-cluster-upgrade-from-783 * open-xchange-cluster-upgrade-from-784 * open-xchange-cluster-upgrade-from-7100-7101 * open-xchange-cluster-upgrade-from-7102 * open-xchange-cluster-upgrade-from-7103-7104 * open-xchange-cluster-upgrade-from-7105

8.10

3rd Party Libraries/License Change

SCR-1139

Summary: Upgraded Socket.IO server components

Effective: applies to the 8.35 release line

Upgraded Socket.IO server components in bundle "com.openexchange.socketio" to support Engine.IO v4 and Socket.IO v3

  • engine.io-server-1.3.5.jar --> engine.io-server-6.1.0.jar
  • socket.io-server-1.0.3.jar --> socket.io-server-4.0.1.jar

API - HTTP-API

SCR-1180

Summary: Allow adding attachments from other mails during mail composition

Effective: applies to the 8.35 release line

The addAttachment action from the module mailcompose of the HTTP API is extended with an additional "origin" within the existing JSON form field of the multipart/form-data payload.

By specifying "mail" as "origin" the client is allowed to add a file attachment from an existing mail message to the composition space

Example:

POST /mailcompose?action=addAttachment
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryyhuRsdTCa7hO6MJ4

------WebKitFormBoundaryyhuRsdTCa7hO6MJ4
Content-Disposition: form-data; name="contentDisposition"

ATTACHMENT
------WebKitFormBoundaryyhuRsdTCa7hO6MJ4
Content-Disposition: form-data; name="JSON"

{"origin":"mail", "id":"40", "folderId":"default0/INBOX", "attachmentId":"2"}
------WebKitFormBoundaryyhuRsdTCa7hO6MJ4--

SCR-1166

Summary: New action "getRecurrence" in Module "chronos"

Effective: applies to the 8.35 release line

In order to supply clients with information whether a change exception is considered as rescheduled or overridden, the new action getRecurrence is introduced in the chronos module of the HTTP API. Prior chosing whether the whole series or just the actual recurrence should be changed by an update operation, this action can be performed to get all necessary information.

Further details are available at https://documentation.open-xchange.com/components/middleware/http/latest/index.html#!Chronos/getRecurrence .

SCR-1162

Summary: New Parameter "includeDelegates" for Action "needsAction" in Module "chronos"

Effective: applies to the 8.35 release line

The needsAction action in the module chronos of the HTTP API is extended by the new URL parameter indludeDelegates.

If set to true, an enhanced response is returned which includes the events needing action of the session user itself, along with the data for other attendees the user has delegate scheduling permissions for. This includes both resource attendees where the user may act as booking delegate for, as well as other attendees where the user has a shared calendar with write access. If the parameter is set to false, only events for the current user are included in the response.

Whenever the parameter is set, an enhanced response in form of an array will be returned, where each element lists the attendee, together with the corresponding events needing action for that attendee. As before, for series events, overridden instances that are not considered as re-scheduled are hidden implicitly in the results. For backwards compatibility reasons, if the parameter includeDelegates is not set in the request, the previous, 'flat' response is returned to clients for the time being.

Further details are available at https://documentation.open-xchange.com/components/middleware/http/latest/index.html#!Chronos/getEventsNeedingAction .

SCR-1154

Summary: Extended resource model with scheduling privileges

Effective: applies to the 8.35 release line

In order to store scheduling privileges for resources of users and groups, the resource object of the HTTP API is extended with an array holding scheduling privileges per user names permissions. Each array element holds a scheduling privilege object which has the following properties: * entity, integer: Internal identifier of the user or group to which this permission applies. * group, boolean: Set true if entity refers to a group, false if it refers to a user * privilege, string: One of ** none - No privileges to book the resource ** ask_to_book - May submit a request to book the resource if it is available ** book_directly - May book the resource directly if it is available ** delegate - Act as delegate of the resource and manage bookings

Additionally, the read-only field own_privilege is introduced for resource objects, which indicates which effective privileges apply for the requesting user.

More details are available at https://documentation.open-xchange.com/components/middleware/http/latest/index.html#!Resources

API - Java

SCR-1170

Summary: Removed publication of TextXtractService and changed interface IMailMessageStorage

Effective: applies to the 8.35 release line

The use of Apache Tika within the Open-Xchange server was reduced to a possible minimum. 

As a result there is no need to keep the publication of 'TextXtractService'. All implementations and the interface will be removed. There was no need to adapt the usage as it just was used in obsolete code.

The last java related change was the removal of the following method from IMailMessageStorage: 

'public String[] getPrimaryContents(String folder, String[] mailIds) throws OXException;'

SCR-1167

Summary: New method "getRecurrenceInfo" within Chronos Stack

Effective: applies to the 8.35 release line

In order to drive the new action getRecurrence of the HTTP API, the Chronos stack is extended with a corresponding method with the following signature:

RecurrenceInfo getRecurrenceInfo(EventID eventID) throws OXException;

Implementations are available for the default internal, as well as the cross-context provider.

SCR-1163

Summary: Adjusted Signature of "getEventsNeedingAction" Method throughout Chronos Stack

Effective: applies to the 8.35 release line

The method #getEventsNeedingAction is adjusted throughout the calendar stack, which includes the compositing layer, as well as the interfaces of the implementing services. A new boolean method parameter named includeDelegates is introduced, and the method response type is now a Map associating Attendee s to their EventsResult s.

API - SOAP

SCR-1161

Summary: Extended SOAP provisioning interface for managed resources

Effective: applies to the 8.35 release line

The resource object for SOAP webservices OXResourceServicePortType and OXResellerResourceServicePortType have been extended for provisioning managed resources. The resource object has now additional permissions parameter:

<xsd:permissions>
   <xsd:entity>2</xsd:entity>
   <xsd:group>0</xsd:group>
   <xsd:privilege>book_directly</xsd:privilege>
</xsd:permissions>

-Also SOAP webservices OXResourceServicePortType and OXResellerResourceServicePortType got new operation removePermissions- Permissions are removed by not mentioning them in resource object

Behavioral Changes

SCR-1160

Summary: Removed direct link from notification mails

Effective: applies to the 8.35 release line

Within the internal notification mails for calendar events, there were direct links pointing to the appointment and (if those existed) for their attachments, for a quicker access.

Those direct links however are static and might be, shortly after the generation, out of date. For example, a user only had to move the appointment to a different calendar and the static link in the notification mail doesn't lead anywhere.

Further, the UI requests, renders and links the current event data on notification mails dynamically, efficiently solving the problem the direct links were created for much better. Thus, there is no need for the direct links anymore.

Configuration

SCR-1181

Summary: New Properties to Control 'used-for-sync" Behavior of Calendar Folders

Effective: applies to the 8.35 release line

In order to control whether public or shared calendar folders are considered for synchronization via CalDAV by default or not, the following new lean configuration properties are introduced with the indicated defaults:

# Configures if shared calendar folders from the default account are considered for 
# synchronization by default or not. May still be set individually by the end user 
# unless also marked as protected.
com.openexchange.calendar.usedForSync.shared.default=true
# Configures if the default value that determines if shared calendar folders from the 
# default account are considered for synchronization may be overridden by the user or not.
com.openexchange.calendar.usedForSync.shared.protected=false
# Configures if public calendar folders from the default account are considered for 
# synchronization by default or not. May still be set individually by the end user 
# unless also marked as protected.
com.openexchange.calendar.usedForSync.public.default=true
# Configures if the default value that determines if public calendar folders from the 
# default account are considered for synchronization may be overridden by the user or not. 
com.openexchange.calendar.usedForSync.public.protected=false

All properties are reloadable and can be configured through the config cascade. With the implicit defaults, no existing semantics are changed, i.e. all shared/public folders of the default account continue to be used for sync by default, overridable by end users.

More details are available at [https://documentation.open-xchange.com/components/middleware/config/latest/#mode=search&term=com.openexchange.calendar.usedForSync] .

SCR-1148

Summary: Allow using multiple services for password-change functionality

Effective: applies to the 8.35 release line

Since we now allow different PasswordChangeServices to be used in parallel, we must have some configuration that enables or disables certain services for certain context/users. Therefore, the following properties were introduced:

com.openexchange.passwordchange.script.enabled=false
com.openexchange.passwordchange.db.enabled=false

The database based password change is disabled by default, reflecting the status before the code changes. In older versions you had to actively install the packages.

SCR-1142

Summary: Helm: Configuration of sensitive mandatory properties

Effective: applies to the 8.35 release line

With MW-1814 we removed the default values for some sensitive properties. As some of those properties are still mandatory, we have updated the ox-common chart to generate secure random values, if no values have been specified (MW-1830). Those values are stored in a k8s secret called <RELEASE>-common-env and will be used by multiple charts/services (e.g. core-mw, core-imageconverter, ...).

The following properties are affected:

com.openexchange.cookie.hash.salt
com.openexchange.share.cryptKey
com.openexchange.sessiond.encryptionKey

From now on, administrators should set those properties in the global section of the deployment's values.yaml file.

Example:

global:
  core:
    cookieHashSalt: "KtLUTLKZrbXvCAOn"
    shareCryptKey: "lJZEFPzUYfapWbXL"
    sessiondEncryptionKey: "auw948cz,spdfgibcsp9e8ri+<#qawcghgifzign7c6gnrns9oysoeivn"

This will create the following k8s secret:

apiVersion: v1
kind: Secret
metadata:
  name: <RELEASE>-common-env
  namespace: <RELEASE>
  annotations:
    helm.sh/resource-policy: "keep"
  labels:
    helm.sh/chart: ox-common-1.0.22
data:
  COOKIE_HASH_SALT: cHlDN3p5RU1kZ0FmT3Znag==
  SHARE_CRYPT_KEY: Ujk5RFFVUGd4TWox
  SESSIOND_ENCRYPTION_KEY: eTY2cGk4azdXdFNpZ1BzTkJhVVIwWm9rN1lHM0M1YTZGVGZLenJkRWd5eVlwMGRuVjVtWjloSDFJUw==

Those environment variables will then be injected into the service containers and written into the relevant .properties files by the individual charts.

Packaging/Bundles

SCR-1182

Summary: Upgraded logback-extensions to 2.1.4

Effective: applies to the 8.35 release line

The logback-extensions library was upgraded to version 2.1.4 which includes some previously missing fields in the json logger.

SCR-1171

Summary: Removed bundles com.openexchange.textxtraction and org.apache.tika

Effective: applies to the 8.35 release line

The use of Apache Tika within the Open-Xchange server was reduced to a possible minimum. As a result the bundles org.apache.tika and com.openexchange.textxtraction will be removed.

SCR-1147

Summary: Allow multiple services for password-change functionality

Effective: applies to the 8.35 release line

With the new version 8.x of the Open Xchange App Suite we moved from package based installations to Docker/Kubernetes. For this, we need to be able to install all packages in parallel within the images we deliver. The different password change implementations however were conflicting. Therefore, we removed those packages and restructured the code.

Removed packages:

open-xchange-passwordchange-database
open-xchange-passwordchange-script

Removed bundles:

com.openexchange.passwordchange.database
com.openexchange.passwordchange.script

Added bundles:

com.openexchange.passwordchange
com.openexchange.passwordchange.common
com.openexchange.passwordchange.impl

The added bundles are now delivered within the open-xchange-core package

The property files change_pwd_script.properties and passwordchange.properties were moved to the bundle com.openexchange.passwordchange.impl alongside the restructuring.

8.35.65

API - HTTP-API

SCR-1525

Summary: Added field "sharedreadonly" to "snippet" module

Effective: 8.35.65 and later

Added field "sharedreadonly" to "snippet" module. It provides the information whether a shared snippet may be seen, but must not be modified/deleted by other users.

{
   "id":"3",
   "content":"...",
   "createdby":3,
   "displayname":"My signature",
   "misc":{
      "insertion":"below",
      "content-type":"text/html"
   },
   "module":"io.ox/mail",
   "type":"signature",
   "shared":false,
   "sharedreadonly":false
}

Database

SCR-1524

Summary: Added column "shared_read_only" to "snippet" table

Effective: 8.35.65 and later

Update Task com.openexchange.snippet.mime.groupware.SnippetAddReadOnlyColumnUpdateTask

Added column "shared_read_only" to "snippet" table. It stores the information whether a shared snippet may be seen, but must not be modified/deleted by other users.

  `shared_read_only` tinyint(3) unsigned NOT NULL DEFAULT 0

Full table layout is now:

CREATE TABLE `snippet` (
  `cid` int(10) unsigned NOT NULL,
  `user` int(10) unsigned NOT NULL,
  `id` varchar(64) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `accountId` int(10) unsigned DEFAULT NULL,
  `displayName` varchar(255) NOT NULL,
  `module` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `type` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `shared` tinyint(3) unsigned DEFAULT NULL,
  `refType` tinyint(3) unsigned NOT NULL,
  `refId` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `lastModified` bigint(64) NOT NULL,
  `size` int(10) unsigned DEFAULT NULL,
  `shared_read_only` tinyint(3) unsigned NOT NULL DEFAULT 0,
  PRIMARY KEY (`cid`,`user`,`id`),
  KEY `indexShared` (`cid`,`shared`),
  KEY `indexRefType` (`cid`,`user`,`id`,`refType`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

8.35.57

Packaging/Bundles

SCR-1522

Summary: Updated Snappy library from v1.1.10.5 to v1.1.10.7

Effective: 8.35.57 and later

Updated Snappy library from v1.1.10.5 to v1.1.10.7 in Target Platform (com.openexchange.bundles)

8.35.55

Configuration

SCR-1521

Summary: Added config switch to keep own address when replying to self-sent message

Effective: 8.35.55 and later

Added new lean boolean property to configure whether to keep own address when replying to self-sent message

  • com.openexchange.mail.keepOwnAddressWhenReplyingToSelfSentMail Define whether to keep own address when replying to self-sent message. Default value is "false". Reloadable and config-cascade aware.

8.35.31

Configuration

SCR-1514

Summary: New property 'com.openexchange.cache.v2.redis.multiKeyLimit'

Effective: 8.35.31 and later

In order to limit the maximum number of addressed keys per MGET, MSET, MHGET or MHSET command, the lean configuration property

com.openexchange.cache.v2.redis.multiKeyLimit

is introduced. It defaults to 100, and is neither reloadable, nor config-cascade aware.

8.35.25

3rd Party Libraries/License Change

SCR-1513

Summary: Update Apache Commons CSV from v1.6 to v1.13.0

Effective: 8.35.25 and later

  • Update Apache Commons CSV from v1.6 to v1.13.0 in target platform (com.openexchange.bundles)
  • Update Apache Commons IO from v1.16.1 to v1.18.0 in target platform (com.openexchange.bundles)

8.35.21

3rd Party Libraries/License Change

SCR-1512

Summary: Updated Apache Commons CLI library from v1.6.0 to v1.9.0

Effective: 8.35.21 and later

Updated Apache Commons CLI library from v1.6.0 to v1.9.0 in target platform (com.openexchange.bundles)

SCR-1511

Summary: Update Apache Commons Codec

Effective: 8.35.21 and later

Update Apache Commons Codec from v.1.17.0 to v1.17.2 in target platform (com.openexchange.bundles)

8.35.17

Configuration

SCR-1510

Summary: Changed defaults for Client-Onboarding YAML configuration file

Effective: 8.35.17 and later

Changed defaults in client-onboarding-scenarios.yml YAML configuration file:

  • Removed sections ** Removed section for identifier mailappinstall referencing discontinued OX Mail App
  • Changed attribute enabled to true ** Changed attribute enabled to true for section driveappinstall (OX Drive App) ** Changed attribute enabled to true for section syncappinstall (Sync App) ** Changed attribute enabled to true for section davsync (CalDAV & CardDAV Sync) ** Changed attribute enabled to true for section davmanual (CalDAV & CardDAV Sync) ** Changed attribute enabled to true for section eassync (Exchange ActiveSync) ** Changed attribute enabled to true for section easmanual (Exchange ActiveSync) ** Changed attribute enabled to true for section mailsync (IMAP/SMTP) ** Changed attribute enabled to true for section mailmanual (IMAP/SMTP)

8.35.13

API - Java

SCR-1509

Summary: Update cxf-libraries to 3.5.10

Effective: 8.35.13 and later

Update cxf-libraries from v3.5.9 to v3.5.10:

  • cxf-core
  • cxf-rt-bindings-soap
  • cxf-rt-bindings-xml
  • cxf-rt-databinding-jaxb
  • cxf-rt-features-logging
  • cxf-rt-frontend-jaxws
  • cxf-rt-frontend-simple
  • cxf-rt-transports-http
  • cxf-rt-ws-addr
  • cxf-rt-wsdl
  • cxf-rt-ws-policy

8.35.12

3rd Party Libraries/License Change

SCR-1507

Summary: Added Apache Aries SPI Fly to target platform

Effective: 8.35.12 and later

Added Apache Aries SPI Fly to target platform. SPI Fly is the Reference Implementation of the OSGi ServiceLoader Mediator specification. This is needed to due to update of logging-related libraries, in which SLF4J changed from static initialization to the usage of Java's java.util.ServiceLoader.

Added bundles to target platform:

  • asm-9.6.jar
  • asm-analysis-9.6.jar
  • asm-commons-9.6.jar
  • asm-tree-9.6.jar
  • asm-util-9.6.jar
  • org.apache.aries.spifly.dynamic.bundle-1.3.7.jar

SCR-1506

Summary: Updated logging-related libraries

Effective: 8.35.12 and later

Updated logging-related libraries in target platform - thereof SLF4J API and Logback as well as associated logging bridges

  • Updated slf4j-api from v1.7.36 to v2.0.16
  • Updated logback-core from v1.2.13 to v1.5.16
  • Updated logback-classic from v1.2.13 to v1.5.16
  • Updated jcl-over-slf4j from v1.7.36 to v2.0.16
  • Updated jul-to-slf4jj from v1.7.36 to v2.0.16
  • Updated log4j-over-slf4j from v1.7.36 to v2.0.16
  • Updated osgi-over-slf4j from v1.7.36 to v2.0.16

Packaging/Bundles

SCR-1508

Summary: Added new SLF4J API fragment bundle

Effective: 8.35.12 and later

Added new SLF4J API fragment bundle org.slf4j.fragment to open-xchange-core package/bundle list.

Purpose of this bundle is to make package ch.qos.logback.classic.spi available to SLF4J API bundle in order to inject Logback's SLF4j service provider into initialization phase of the SLF4J logging runtime.

8.35.10

Configuration

SCR-1499

Summary: Added new properties to configure the new async framework

Effective: 8.35.10 and later

The new async framework introduces a few new lean properties which control the behaviour of framework.

  • com.openexchange.admin.ctx.async.enabled Enables asynchronous deletion of contexts. Default value is false and config-cascade aware.
  • com.openexchange.admin.async.schedule The schedule to run async admin operations. No default value and not config-cascade aware.
  • com.openexchange.admin.async.pool.size The size of the threadpool which is responsible to run async tasks. The greater the pool the more tasks can be executed in parallel. Default value is 10 and not config-cascade aware.
  • com.openexchange.admin.async.refresh.interval The interval in minutes in which claims of running tasks are refreshed. This must always be lower than com.openexchange.admin.async.retry.interval. Default value is 5 and not config-cascade aware.
  • com.openexchange.admin.async.retry.limit The amount of times a failed async task is tried to be repeated. Default value is 5 and not config-cascade aware.
  • com.openexchange.admin.async.retry.interval Defines the interval in minutes after a task is considered stale. Or in other words a task is considered stale if: now > last update + interval. Default value is 15 and not config-cascade aware.
  • com.openexchange.admin.async.refill.interval Defines the interval in minutes in which new tasks are added to the queue of available tasks. This happens only during the defined schedule (see com.openexchange.admin.async.schedule). Default value is 5 and not config-cascade aware.
  • com.openexchange.admin.async.cleanup.retentionDays The maximum amount of days a task is stored. Default value is 730 and not config-cascade aware.
  • com.openexchange.admin.async.cleanup.interval The interval between runs of the cleanup task. A value of 0 disables the task. Default value is 7 and not config-cascade aware.

Database

SCR-1497

Summary: Added a new table async_tasks to the configdb database

Effective: 8.35.10 and later

Update Task 8:addAsyncTasksTable

The new async framework introduces a new table async_tasks in the configdb which is responsible to store asynchronous tasks.

That table is created by the liquibase task 8:addAsyncTasksTable.

CREATE TABLE `async_tasks` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `entityId` varchar(100) NOT NULL,
  `type` varchar(100) NOT NULL,
  `args` text DEFAULT NULL,
  `state` varchar(100) NOT NULL,
  `lastUpdate` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `claim` BINARY(16) DEFAULT NULL,
  `retryCount` int unsigned NOT NULL DEFAULT 0,
  `error` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `entity_type_unique` (`entityId`,`type`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Packaging/Bundles

SCR-1498

Summary: Added the new bundle com.openexchange.admin.async

Effective: 8.35.10 and later

For the new async framework the new bundle "com.openexchange.admin.async" is added to the open-xchange-admin package

8.34

8.35.0

API - Java

SCR-1496

Summary: Enhanced OAuthAuthorizationService#validateAccessToken with Header collection parameter

Effective: 8.35.0 and later

The method com.openexchange.oauth.provider.authorizationserver.spi.OAuthAuthorizationService#validateAccessToken is enhanced with the additional parameter com.openexchange.servlet.Headers holding the headers of the underlying HTTP servlet request that is used to trigger the authentication request.

A default implementation of the new method overload is added, which delegates to the existing method passing the extracted access tokens only.

SCR-1496

Summary: Enhanced OAuthAuthorizationService#validateAccessToken with Header collection parameter

Effective: 8.35.0 and later

The method com.openexchange.oauth.provider.authorizationserver.spi.OAuthAuthorizationService#validateAccessToken is enhanced with the additional parameter com.openexchange.servlet.Headers holding the headers of the underlying HTTP servlet request that is used to trigger the authentication request.

A default implementation of the new method overload is added, which delegates to the existing method passing the extracted access tokens only.

Configuration

SCR-1486

Summary: New property com.openexchange.carddav.addressbookMultigetLimit

Effective: 8.35.0 and later

The lean configuration property com.openexchange.carddav.addressbookMultigetLimit is introduced to configure the maximum number of elements included in CARDDAV:addressbook-multiget responses to the client.

If data from more elements was requested, HTTP/1.1 507 Insufficient Storage responses will get inserted. It defaults to 1000, a value of -1 disabled the limit. Property is reloadable and can be defined through the config-cascade.

SCR-1486

Summary: New property 'com.openexchange.carddav.addressbookMultigetLimit'

Effective: 8.35.0 and later

The lean configuration property com.openexchange.carddav.addressbookMultigetLimit is introduced to configure the maximum number of elements included in CARDDAV:addressbook-multiget responses to the client.

If data from more elements was requested, HTTP/1.1 507 Insufficient Storage responses will get inserted. It defaults to 1000, a value of -1 disabled the limit. Property is reloadable and can be defined through the config-cascade.