App Suite Middleware
8.52.305
Changed defaults
SCR-1998
Summary: More carrier threads for virtual threads by default
Effective: 8.52.305 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.
8.52.298
Behavioral Changes
SCR-1973
Summary: Custom trust store is now honoured alongside the JVM's default trust store
Effective: 8.52.298 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.
Configuration
SCR-1967
Summary: New properties to configure authentication and TLS for the Cassandra connection
Effective: 8.52.298 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 allcom.openexchange.nosql.cassandra.password- the accompanying passwordcom.openexchange.nosql.cassandra.authProviderClass- the driver's authentication provider,PlainTextAuthProviderby defaultcom.openexchange.nosql.cassandra.ssl- encrypts the connections using TLS,falseby defaultcom.openexchange.nosql.cassandra.sslKeystorePathandcom.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.
8.52.287
API - HTTP-API
SCR-1818
Summary: New HTTP API action mail?action=emlToken to download a message as .eml file without a session
Effective: 8.52.287 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.
folderandididentify the message and are mandatory.ttlMillisshortens the token's lifetime; a value above the configured default is capped to it.oneTimeinvalidates the token once it has been redeemed, defaultfalse.checkIprestricts the download to the client address the token was issued for, defaultfalse.
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.
Configuration
SCR-1819
Summary: New properties for eml token lifetime, message size limit and concurrent token downloads
Effective: 8.52.287 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.ttlsets how long a token issued throughmail?action=emlTokenstays valid, defaulting to300000milliseconds. 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.maxMessageSizerefuses to issue such a token for messages larger than1073741824bytes. 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 to0disables the check.com.openexchange.mail.attachmentToken.maxConcurrentDownloadsbounds how many token downloads one user may have in flight at the same time on one node, defaulting to20. It covers downloads of single attachments as well as of whole messages through/ajax/mail.attachment; requests beyond the limit are answered with status429. A value less than or equal to0disables 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.
8.52.286
Configuration
SCR-1900
Summary: New lean configuration property com.openexchange.push.dovecot.unregisterOnMissingSession
Effective: 8.52.286 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.
8.52.285
Configuration
SCR-1892
Summary: New configuration option for caching the master administrator's password verification on provisioning calls
Effective: 8.52.284 and later; also delivered in 8.52.285
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.masterPasswordVerificationTtlSecondsSpecifies how long (in seconds) a successful verification of the master administrator's password is remembered on a node. A value less than or equal to0(zero) disables the cache and verifies the password hash on every call. Default300. Reloadable, not config-cascade aware. No dedicated properties file.
8.52.284
Configuration
SCR-1892
Summary: New configuration option for caching the master administrator's password verification on provisioning calls
Effective: 8.52.284 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.masterPasswordVerificationTtlSecondsSpecifies how long (in seconds) a successful verification of the master administrator's password is remembered on a node. A value less than or equal to0(zero) disables the cache and verifies the password hash on every call. Default300. Reloadable, not config-cascade aware. No dedicated properties file.
8.52.283
Behavioral Changes
SCR-1886
Summary: Readable 403 page for OpenID Connect logins declined because the user or context is disabled
Effective: 8.52.283 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.
8.52.282
Behavioral Changes
SCR-1885
Summary: Cache invalidations cross remote Redis sites
Effective: 8.52.282 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.
Configuration
SCR-1884
Summary: New configuration options for remote Redis sites
Effective: 8.52.282 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.scopeWhat 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. Useinvalidationfor clusters that merely share the databases. Defaultall. Not reloadable, not config-cascade aware. File:redis.properties.com.openexchange.redis.[site].cache.enabledWhether the remote site denoted by[site](one of the identifiers listed incom.openexchange.redis.sites) runs a dedicated Redis instance for cache data. If enabled, that instance is configured through the[site].cacheinfix, 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. Defaultfalse. Not reloadable, not config-cascade aware. File:redis.properties.
8.52.277
Configuration
SCR-1877
Summary: New configuration option for contact auto-complete result limiting
Effective: 8.52.277 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.maxResultsDefines the maximum number of contacts returned by anaddressbooks?action=autocompleterequest that does not supply aright_hand_limitof 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.
8.52.273
API - HTTP-API
SCR-1875
Summary: New optional parameter applyDefaultAlarms for the iCal import request
Effective: 8.52.272 and later; also delivered in 8.52.273
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.
8.52.272
API - HTTP-API
SCR-1875
Summary: New optional parameter applyDefaultAlarms for the iCal import request
Effective: 8.52.272 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.
8.52.262
Configuration
SCR-1854
Summary: New property com.openexchange.calendar.useNoReplyAddressForNotifications
Effective: 8.52.262 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.
8.52.250
API - HTTP-API
SCR-1844
Summary: New deputy module action reverseIds that lists the granting users without resolving grant details
Effective: 8.52.250 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, or0for a cross-context grantor whose bare identifier has no meaning in the requesting user's contextgrantorIdentifier- the qualified identifier as<userId>@<contextId>grantorEntityInfo- pre-resolved entity information for rendering the grantordeputyIds- the identifiers of the deputy permissions this user grantedsendOnBehalfOf- 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 grantgrantorAddresses- the addresses to send from, present only whensendOnBehalfOfistrue; 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.
8.52.249
API - HTTP-API
SCR-1844
Summary: New deputy module action reverseIds that lists the granting users without resolving grant details
Effective: 8.52.249 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, each with the identifiers of the grants they made, 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.
Each element of the returned array carries:
grantorId- the identifier of the granting user, or0for a cross-context grantor whose bare identifier has no meaning in the requesting user's contextgrantorIdentifier- the qualified identifier as<userId>@<contextId>grantorEntityInfo- pre-resolved entity information for rendering the grantordeputyIds- the identifiers of the deputy permissions this user granted
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"
]
}
]
}
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.
Configuration
SCR-1843
Summary: New configuration options for capping how long IMAP responses are read from the primary and secondary account
Effective: 8.52.249 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.readResponsesTimeoutThe 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 to0is 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.readResponsesTimeoutThe same for secondary accounts. A value less than or equal to0is 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.
8.52.240
Behavioral Changes
SCR-1826
Summary: New metrics for the Redis circuit breakers and bulkhead
Effective: 8.52.240 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.
Configuration
SCR-1827
Summary: New configuration options for the Redis connector start-up behavior
Effective: 8.52.240 and later
Two configuration options control how the Redis connector behaves while its bundle starts.
com.openexchange.redis.awaitEndPointOnStartupWhether bundle start-up awaits reachability of the Redis end-point. With the default the connector blocks until the end-point answers. Setting it tofalsemoves 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 theRedisConnectorServiceis 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.awaitEndPointBudgetMillisHow long start-up awaits the Redis end-point before giving up, in milliseconds. Only relevant whilecom.openexchange.redis.awaitEndPointOnStartupistrue. 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.
8.52.239
Configuration
SCR-1825
Summary: New configuration option for Redis Sentinel authentication
Effective: 8.52.239 and later
In order to connect to a password-protected Redis Sentinel, a new configuration option has been added.
com.openexchange.redis.sentinel.passwordSpecifies the password used to authenticate against the Redis Sentinel nodes. Only effective ifcom.openexchange.redis.modeis set tosentinel. Sentinel authentication is separate from the credentials for the Redis nodes themselves, which remain configured throughcom.openexchange.redis.usernameandcom.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 theAUTHcommand and the topology look-up fails. For a special Redis instance the option is available ascom.openexchange.redis.[instanceId].sentinel.password, with[instanceId]beingcacheor the identifier of a remote site. Default empty. Not reloadable, not config-cascade aware. File: redis.properties.
8.52.237
General
SCR-1822
Summary: Added command-line tool threaddump that covers virtual threads
Effective: 8.52.235 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>
8.52.226
Behavioral Changes
SCR-1814
Summary: Reseller ownership and restrictions are now enforced when copying a user
Effective: 8.52.226 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.
8.52.216
Behavioral Changes
SCR-1723
Summary: Java 25: virtual-thread HTTP worker pool and opt-in generational ZGC
Effective: applies to the 8.52 release line
The middleware now runs on Java 25. Grizzly HTTP workers use virtual threads by default (com.openexchange.http.grizzly.virtualThreadsEnabled=true) and Compact Object Headers are on. No admin action required: G1 stays the default garbage collector, so existing memory sizing still fits. Generational ZGC is opt-in via the Helm value javaOpts.zgc - faster in the load test (mean 38 vs 56 ms, p99 213 vs 796 ms, +47% throughput), but it needs sizing: 4G heap on a 6G limit with MALLOC_ARENA_MAX=2 and enough CPU. Too little memory surfaces as failing IMAP/SMTP connections rather than as an OOM. Changed worker-pool defaults: com.openexchange.threadpool.maximumPoolSize 2000 (was unbounded), workQueue linked (was synchronous), virtual.maxConcurrency auto (was 20000). Details: https://documentation.open-xchange.com/8/middleware/administration/garbage_collection_and_memory_sizing.html
8.52.197
Configuration
SCR-1803
Summary: New properties for the replication monitor's replica status check
Effective: 8.52.197 and later
The replication monitor now probes read replicas' replication status (SHOW SLAVE STATUS) and redirects reads to the master while a replica reports broken replication or excessive lag. This closes the gap that a re-seeded or inconsistently restored replica could serve incomplete data undetected (middleware/core#4, follow-up to the incident behind appsuite/support#1599). Four new lean configuration properties control the behavior:
com.openexchange.database.replicationMonitor.checkReplicaStatus(default: true) - Whether to watch read replicas for broken or excessively lagging replication and redirect reads to the master meanwhile. Works out of the box: where the REPLICA MONITOR (MariaDB) or REPLICATION CLIENT (MySQL) privilege is available, the replication status statement provides fast, precise detection; without it the check falls back to a privilege-free heartbeat, a time stamp periodically written through the replication channel into the replicationMonitor table (reserved row cid=4294967295), needing only the regular INSERT/UPDATE/SELECT permissions.REPLICA MONITOR(MariaDB) or REPLICATION CLIENT (MySQL) privilege; both are global privileges, so one grant per database host covers all existing and future schemas, and initconfigdb -a now grants them automatically. Without the privilege the check suspends itself for the affected pool. Only effective if the replication monitor is active. Default: true. Reloadable: false. Config-cascade aware: false.com.openexchange.database.replicationMonitor.maxReplicaLag- Maximum tolerated replication lag in seconds before reads are redirected to the master. Default: 300. Reloadable: false. Config-cascade aware: false.com.openexchange.database.replicationMonitor.replicaStatusCheckInterval- Minimum number of seconds between two replication status probes per read pool. Default: 10. Reloadable: false. Config-cascade aware: false.com.openexchange.database.replicationMonitor.requireReplication- Whether a read host that does not act as a replica at all (emptySHOW SLAVE STATUS) is considered unhealthy. Keep false for Galera or multi-primary setups; set to true where read pools are always asynchronous replicas. Default: false. Reloadable: false. Config-cascade aware: false.
All four properties are read once at middleware start-up; changing them requires a restart. They are server-scoped (no config-cascade evaluation) and documented in documentation-generic/config/ConfigDB.yml. Defaults are safe for every topology: without the privilege or without asynchronous replication the check fails open and behavior is unchanged.
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
httpclient55.6.2,httpcore55.4.3 andhttpcore5-h25.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.webhookas 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/xmpboxupgraded from 2.0.27 to 3.0.7 (new companion artifactpdfbox-io)Unused
pdfbox-toolsandpreflightembeds removed (never referenced by code)pdfbox2-layout1.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 APITarget platform
pdfbox/fontbox2.0.30 upgraded to 3.0.7 (+pdfbox-io); consumed byopenexchange-test(ExportPDFTest)Code migrated to the PDFBox 3 API:
Loader.loadPDFinstead ofPDDocument.load,Standard14Fonts.FontNamebased font construction,MemoryUsageSetting.streamCache,PDPageContentStream.AppendMode, xmpboxcreateAndAddPDFAIdentificationSchema
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-coreis split intoopensaml-core-api/opensaml-core-implupstream)net.shibboleth.utilities:java-support7.5.1 replaced by the modularnet.shibbolethshared libraries 9.2.3 (shib-support/shib-security/shib-networking/shib-velocity); exported packages move fromnet.shibboleth.utilities.java.support.*tonet.shibboleth.shared.*xmlsecupgraded from 2.3.4 to 3.0.6,metrics-corefrom 3.1.2 to 4.2.39New embedded transitives
httpclient55.3.1/httpcore55.2.5 (required by the OpenSAML 5 initialization service)Obsolete
joda-timeusage migrated tojava.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.1google-api-client(+ appengine/gson/jackson2/protobuf/servlet/xml modules) upgraded from 2.2.0 to 2.9.0google-oauth-client(+ appengine/java6 modules) upgraded from 1.34.1 to 1.39.0google-api-servicescalendar/drive/gmail/people upgraded to current revisions (rev20260614/rev20260624/rev20260525/rev20251117); oauth2 unchanged upstreamapi-commonupgraded from 2.15.0 to 2.65.0grpc-contextupgraded from 1.27.2 to 1.70.0 (new companiongrpc-api1.70.0)- New embedded transitive:
google-auth-library-credentials/google-auth-library-oauth2-http1.47.0 firebase-adminupgraded from 9.2.0 to 9.10.0; its default HTTP transport (ApacheHttp2Transport) requires embeddinghttpclient55.3.1,httpcore55.2.4 andhttpcore5-h25.2.4;nimbus-jose-jwtis 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.2jakarta.xml.ws-api-3.0.1.jarupgraded tojakarta.xml.ws-api-4.0.3.jarjaxws-rt-3.0.2.jar(Metro) upgraded tojaxws-rt-4.0.5.jarsaaj-impl-2.0.1.jarupgraded tosaaj-impl-3.0.6.jarneethi-3.2.1.jarupgraded toneethi-3.2.2.jar,xmlschema-core-2.3.1.jartoxmlschema-core-2.3.2.jar,gmbal-api-only-4.0.3.jartogmbal-api-only-4.1.2.jar,mimepull-1.9.15.jartomimepull-1.11.0.jar,streambuffer-2.0.2.jartostreambuffer-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.jarupgraded tospring-core-7.0.8.jarspring-beans-6.2.15.jarupgraded tospring-beans-7.0.8.jarspring-jcl-6.2.15.jarremoved (merged into spring-core in Spring Framework 7)joox-1.5.0.jarupgraded tojoox-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.jarupgraded tohazelcast-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.jarupgraded toesapi-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.jarupgraded tobox-java-sdk-4.16.4.jar(latest release of the classiccom.box.sdkAPI line; the 10.x line is a different, generated SDK with a new API)jose4j-0.5.5.jarupgraded tojose4j-0.9.4.jarzstd-jni-1.5.7-2.jarnewly 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.jarupgraded todropbox-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.jarupgraded to 6.1.0;ws-commons-util-1.0.2.jarupgraded tows-commons-util-1.1.0.jarcom.openexchange.eas.provisioning.action.sms:xmlrpc-client-5.0.0.jar,xmlrpc-common-5.0.0.jarupgraded to 6.1.0;ws-commons-util-1.0.2.jarupgraded tows-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.jarupgraded tolib-recur-0.17.1.jarjems2-2.23.1.jarnewly 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.jarupgraded toez-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.jarupgraded torome-2.1.0.jar,rome-utils-1.19.0.jarupgraded torome-utils-2.1.0.jar(rome-fetcherstays at 1.19.0, no 2.x release exists)com.openexchange.server:jaudiotagger-2.2.5.jarupgraded tojaudiotagger-3.0.1.jarcom.openexchange.oauth.provider.impl:caffeine-2.8.5.jarupgraded tocaffeine-3.2.4.jarcom.openexchange.geolocation.maxmind.binary:geoip2-2.17.0.jarupgraded togeoip2-5.1.0.jar,maxmind-db-2.1.0.jarupgraded tomaxmind-db-4.1.0.jarcom.openexchange.sms:libphonenumber-8.13.1.jarupgraded tolibphonenumber-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.jarupgraded towebauthn-server-core-2.9.0.jar,yubico-util-2.5.3.jarupgraded toyubico-util-2.9.0.jario.lettuce:reactor-core-3.6.6.jarupgraded toreactor-core-3.8.6.jarnet.openhft.hashing:zero-allocation-hashing-0.16.jarupgraded tozero-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.jarupgraded tobcmail-jdk18on-1.84.jarbcpg-jdk18on-1.79.jarupgraded tobcpg-jdk18on-1.84.jarbcpkix-jdk18on-1.79.jarupgraded tobcpkix-jdk18on-1.84.jarbcprov-jdk18on-1.79.jarupgraded tobcprov-jdk18on-1.84.jarbcutil-jdk18on-1.79.jarupgraded tobcutil-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.jarupgraded toliquibase-core-5.0.3.jaropencsv-5.11.2.jarupgraded toopencsv-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.jarkubernetes-client-api-7.8.0.jarkubernetes-httpclient-jdk-7.8.0.jarkubernetes-model-admissionregistration-7.8.0.jarkubernetes-model-apiextensions-7.8.0.jarkubernetes-model-apps-7.8.0.jarkubernetes-model-autoscaling-7.8.0.jarkubernetes-model-batch-7.8.0.jarkubernetes-model-certificates-7.8.0.jarkubernetes-model-common-7.8.0.jarkubernetes-model-coordination-7.8.0.jarkubernetes-model-core-7.8.0.jarkubernetes-model-discovery-7.8.0.jarkubernetes-model-events-7.8.0.jarkubernetes-model-extensions-7.8.0.jarkubernetes-model-flowcontrol-7.8.0.jarkubernetes-model-gatewayapi-7.8.0.jarkubernetes-model-metrics-7.8.0.jarkubernetes-model-networking-7.8.0.jarkubernetes-model-node-7.8.0.jarkubernetes-model-policy-7.8.0.jarkubernetes-model-rbac-7.8.0.jarkubernetes-model-resource-7.8.0.jarkubernetes-model-scheduling-7.8.0.jarkubernetes-model-storageclass-7.8.0.jarzjsonpatch-7.8.0.jarsnakeyaml-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.jarnetty-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.jarnetty-codec-http2-4.2.15.Final.jarnetty-codec-http-4.2.15.Final.jarnetty-codec-marshalling-4.2.15.Final.jar(new)netty-codec-protobuf-4.2.15.Final.jar(new)netty-codec-socks-4.2.15.Final.jarnetty-codec-xml-4.2.15.Final.jar(new)netty-common-4.2.15.Final.jarnetty-handler-4.2.15.Final.jarnetty-handler-proxy-4.2.15.Final.jarnetty-resolver-4.2.15.Final.jarnetty-resolver-dns-4.2.15.Final.jarnetty-transport-4.2.15.Final.jarnetty-transport-native-unix-common-4.2.15.Final.jarnetty-transport-classes-epoll-4.2.15.Final.jarnetty-transport-native-epoll-4.2.15.Final.jarnetty-transport-classes-io_uring-4.2.15.Final.jar(new native transport classes)netty-transport-classes-kqueue-4.2.15.Final.jarnetty-transport-native-kqueue-4.2.15.Final.jarnetty-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.jarredis-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), viaEntity.toFormattedString()(com.openexchange.dav.mixins.PrincipalURL).UserPrincipalCollection/GroupPrincipalCollectionparse 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 as404(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
inviteproperty: 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'sEntityInfo(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>ormailto:<email>; supersedesuserIdwhen present.GrantedDeputyPermission(response) —identifier(deputy) andgrantorIdentifier(grantor) as<userId>@<contextId>; the bareuserId/grantorIdare 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-accountentityInfoblock. Absent for a group deputy; for a foreign entity the numericentityis omitted and only the qualifiedidentifieris carried.GrantedDeputyPermission.grantorEntityInfo(response;action=reverse) — the counterpart ofentityInfofor the granting user, so the deputy can render a (possibly foreign-context) grantor.- Available-deputy-modules action: new optional
extended=truereturns objects with acrossContextflag per module (trueonly formail/calendarwhen 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 fielduser_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 numericINTERNAL_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) ormailto:<email>(resolved via aPrincipalUriResolver). A foreign principal is admitted only if the cross-context authority permits, elseFLD-1053(PERMISSION_DENIED_CROSS_CONTEXT). - Read:
identifieris always present (qualified form); the numericentityis written only for local principals (masked for foreign). Extended folder/file permissions surface a foreign principal viaidentifier/EntityInfoand do not anonymize it under a guest session. - The same
identifiersemantics 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} andGET /inbound/{context}/{user} — what a principal received (per-module liaisons, trust zones, mail-share owners).DELETE /inbound/{context}/{user} — purge received access; filtersfrom/owner/module; unconditional operator override (does not consult the authority).GET /outbound/{context}/{user} andDELETE /outbound/{context}/{user} — what a principal granted out, and purge it; filtersto/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— qualifiedEntity entity(id + context).DeputyPermissionDescription—entityContextId(withsetEntityContextId/removeEntityContextId/isEntityContextSetflag accessors).Granter— qualifiedEntity entity;equals/compareToconsider 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.trustZonestags 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.reenforceOnReadremoved;CrossContextAuthorityProvider.isReadReenforcementEnabledhard-wiredfalse; dormant code retained). - Mail same-server — requires
com.openexchange.mail.crossContextPermissions(defaultfalse) and, whencom.openexchange.mail.crossContextRequireSameServer(defaulttrue), 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.PUBLICfolders are accepted; private/shared folders are rejected (OXFolderExceptionCode.NOT_A_PUBLIC_FOLDER). - Bulk mode (
--from-user) is scoped to the public folder subtrees - belowSYSTEM_PUBLIC_FOLDER_ID(public groupware folders) andSYSTEM_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.maxLifetimeSecondsMaximum 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 of0(zero) disables max. lifetime recycling. Default3600(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 RedisCLIENT 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);globalat 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. Defaulttrue.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). Defaulttrue.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). Defaulttrue.
(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
Warning
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
Warning
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); indexprincipal(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
Warning
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_cidvirtualPermission,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
Warning
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(DatabaseCleanUpServicejob, 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). Activatorcom.openexchange.crosscontext.impl.osgi.CrossContextActivator.com.openexchange.chronos.provider.crosscontext— cross-context calendar provider (account reconciler, iTip conversion, incoming-scheduling listener). Activatorcom.openexchange.chronos.provider.crosscontext.osgi.CrossContextCalendarProviderActivator.
See the feature documentation for further details.
8.52.182
Behavioral Changes
SCR-1791
Summary: Guarded loads in Redis cache v2: cache re-inserts that raced an invalidation are rejected
Effective: 8.52.182 and later
Read-aside caching in cache.v2 had an inherent read-load-put race: a load that started before a data change could re-insert the pre-change state right after the invalidation following the change, poisoning the shared Redis cache until the next invalidation or expiration (core#545). Provisioning changes such as capability toggles could therefore remain ineffective on middleware nodes for an unbounded time. The lease/fencing-token pattern ("guarded loads") is now implemented centrally in the Redis-backed cache v2. Every invalidation of a guarded cache region rotates random guard tokens with a one-hour TTL before deleting the cache entries; each key is protected by a pair of guards - a per-key guard rotated by exact-key invalidations and a scope guard rotated by wild-card, group and mass invalidations that cannot enumerate every key they cover. The load path snapshots both guard tokens together with the value in a single Redis operation after a cache miss and before the loader runs, and the loaded value is only put into cache through an atomic Lua script while both tokens are still unchanged; otherwise the put is rejected - the value is still returned to the caller but kept out of the Redis, in-memory and thread-local layers. Values whose load raced a recent invalidation of their guard scope are cached with a capped expiration of 300 seconds, bounding the staleness of values loaded from a lagging read-only database connection. The manual mget-load-mput pattern is covered through per-thread guard token snapshots with batched, pipelined conditional puts. Guard keys share the value key's hash tag, so the scripts are Redis Cluster safe; keys lacking a common hash tag fall back to a non-atomic guard check. Cache hits still cost one round trip. Guarded loads are opt-in via CacheOptions.Builder#withGuardedLoads(boolean) or the new guarded-loads attribute of CoreModuleName, and are enabled for the provisioning-invalidated core regions alias, caps, fs, group, usr, usrIapLgi, usrLgi, permBits and usm; the key infix "guard" is reserved and must not be used as a cache module name. Rejected puts are counted via the new Micrometer metric appsuite.redis.cache.puts.rejected.total, tagged per cache module. Known limitation: region-wide invalidation patterns without a concrete key scope only place guard tokens for keys currently present in cache, so an in-flight load for a key not cached at that moment is not rejected; scoped invalidations do not have this limitation. The interim mitigation of a deferred second invalidation is removed again.
8.52.139
Configuration
SCR-1800
Summary: New property to obtain IMAP subscription state from separate LSUB when the \Subscribed attribute of LIST-EXTENDED responses is untrustworthy
Effective: 8.52.139 and later
On IMAP servers advertising the LIST-EXTENDED capability (RFC 5258) the middleware determines mailbox subscriptions from the single consolidated command LIST "" "" RETURN (SUBSCRIBED CHILDREN [SPECIAL-USE]). Certain proxy setups, for instance Dovecot with an imapc backend (see /appsuite/support#1543 and DOP-3897), answer the SUBSCRIBED return option inconsistently with LSUB: subscribed mailboxes in shared and user namespaces are listed without the \Subscribed attribute, so subscriptions to shared folders never become visible in App Suite. The new lean configuration property com.openexchange.imap.considerSubscribedInListExtended (default true, reloadable, server scope, no .properties file entry) controls this. With true the attribute is trusted and the subscription state comes from the single consolidated round-trip, which is the behavior as before. With false a hybrid mode applies: the consolidated command without SUBSCRIBED still provides hierarchy, children and special-use information while a separate LSUB "" "" provides the subscription state. With probe the middleware verifies once per IMAP server whether the attribute matches the LSUB output and caches the verdict per server, its lifetime governed by com.openexchange.imap.cache.commonImapServerCacheTimeToLive; a probe is only conclusive if it finds a mismatch or covers at least one subscribed mailbox inside a shared or user namespace, and it costs no additional IMAP round-trip compared to hybrid mode. The property only takes effect on servers advertising LIST-EXTENDED, since without that capability separate LIST and LSUB commands are issued anyway. No operator action is required by default; set the property to false or probe for installations whose IMAP server or proxy reports the \Subscribed attribute unreliably.
8.52.23
Configuration
SCR-1777
Summary: Enable client-side prepared statement caching by default (cachePrepStmts)
Effective: 8.52.23 and later
Enables MySQL Connector/J client-side prepared statement caching by default in the middleware database connector. The JDBC connection properties cachePrepStmts=true, prepStmtCacheSize=250 and prepStmtCacheSqlLimit=2048 are now set both as code default in Configuration.readJdbcProps and in the shipped com.openexchange.database/conf/dbconnector.yaml. JFR profiling under sustained load showed prepareStatement re-parsing the SQL text on every call, accounting for roughly 6% CPU, because client-side statement caching was never enabled; with useServerPrepStmts=false, which is the default, Connector/J caches the parsed client-side statement per connection once cachePrepStmts is set. The cache keys on the SQL text only and carries no metadata, so it stays valid across DDL, and the additional memory is bounded to prepStmtCacheSize entries per physical connection. Existing deployments with a customized dbconnector.yaml still get the new default via the code default, and everything remains overridable via dbconnector.yaml or the com.openexchange.database.jdbc.* properties.
8.52.14
Configuration
SCR-1760
Summary: Changed behavior of blocking thread pool task submission
Effective: 8.52.14 and later
The global thread pool executor was reworked to build upon the JDK's java.util.concurrent.ThreadPoolExecutor, which changes one operator-visible behavior for deployments that enable blocking task submission. With com.openexchange.threadpool.blocking=true, a saturated pool now creates additional worker threads up to com.openexchange.threadpool.maximumPoolSize before the submitting caller blocks waiting for queue space; previously the caller already blocked once com.openexchange.threadpool.corePoolSize threads existed, so the pool effectively never grew beyond the core size in blocking mode. While waiting for queue space, a submitting thread's interrupt is now preserved instead of being swallowed. Only non-default configurations are affected: blocking defaults to false, and with the shipped defaults (workQueue=linked and corePoolSize below maximumPoolSize) the property is not effective at all - the change is only observable when blocking=true is combined with workQueue=synchronous or a fixed-size pool. No configuration change is required, but deployments relying on the old implicit thread cap in blocking mode should review maximumPoolSize since the pool may now grow up to that limit under sustained load.
8.52.9
CLT
SCR-1753
Summary: New command-line tool reassignpersonalfolderowners
Effective: 8.52.9 and later
New command-line tool reassignpersonalfolderowners reassigns the owner of all folders located below a user's personal (default) Infostore folder to that user. Since the file storage quota is accounted to the folder owner, this lets everything below a user's personal folder count against that user's quota, aligning already existing folders with the behavior enabled through com.openexchange.infostore.setPersonalFolderOwnerBelowPersonalInfostore (see SCR-1751), which only affects newly created or moved folders. Usage: reassignpersonalfolderowners [-c <contextId> [-u <userId>] ]( --all) [--dry-run] -A <admin> -P <password> [-p <RMI-Port>] [-s <RMI-Server>], where -c processes one context (context admin credentials suffice), -u restricts to a single user, --all processes all contexts (master admin credentials required) and --dry-run only reports affected folders. The tool is idempotent, relocates files between file storages when the previous and the new owner use different ones, and is served via the new RMI service PersonalFolderOwnersRMIService; recalculatefilestoreusage should be run afterwards. The owner reassignment only serves the quota accounting: explicit folder permissions are left untouched, and the administrative access a folder's owner implicitly holds is preserved for the former owner as an explicit folder administrator permission (guest users excluded).
Configuration
SCR-1751
Summary: New property com.openexchange.infostore.setPersonalFolderOwnerBelowPersonalInfostore
Effective: 8.52.9 and later
New lean property com.openexchange.infostore.setPersonalFolderOwnerBelowPersonalInfostore (Boolean, default false; reloadable and config-cascade aware at context level). When enabled, a folder created below a user's personal (default) Infostore folder gets that personal folder's owner assigned regardless of who creates it, and folders moved into or out of such a subtree get their owner - including subfolders - adjusted accordingly, in analogy to the existing com.openexchange.infostore.setAdminAsCreatorForPublicDriveFolder behavior for the public Infostore subtree. Since the file storage quota is accounted to the folder owner, this lets everything below a user's personal folder count against that user's quota. Only newly created or moved folders are affected; existing data is left untouched. To enable the feature, set the property to true, run the new command-line tool reassignpersonalfolderowners once (see SCR-1753) and then recalculatefilestoreusage. The owner reassignment only serves the quota accounting: explicit folder permissions are left untouched, and the administrative access a folder's owner implicitly holds is preserved for the former owner as an explicit folder administrator permission (guest users excluded).
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
/etc/ssl/certs/java/cacertsis now0444(read-only). Custom truststore hooks doingcp … && keytool -import …must addchmod 0644between the two steps.- No
apt-get/dpkgat runtime. Usekubectl debugor the appsuite-toolkit for in-pod investigation; installing packages live is no longer possible. - 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.
- Implicit Debian tools are no longer present:
which,diff,xz,wget, and thehostnamebinary. Customer scripts using these need POSIX alternatives (command -vforwhich,$HOSTNAMEforhostname). - 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.
mysqlis now a symlink tomariadb, 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.