App Suite Releases
  • 8.47
  • 8.35
  • 7.10.6
Imprint
  • 8.47
  • 8.35
  • 7.10.6
Imprint
  • Release 8.52Upcoming
    • Noteworthy Changes
      • Important Changes
      • App Suite Middleware
      • OX Documents
    • Changelogs
      • App Suite UI
      • App Suite Middleware
      • Additional Components
        • AI Service
        • Booking Service
        • OX Guard UI
        • OX Documents
        • Switchboard
        • Changelog
    • Helm Charts
      • AI-Service documentation
      • App Suite Stack Chart
      • Booking
      • Helm Chart core-cacheservice
      • Helm Chart core-documentconverter
      • Helm Chart core-imageconverter
      • core-mw
      • UI Service
      • Switchboard
  • Release 8.51
  • Release 8.50
  • Release 8.49
  • Release 8.48
  • Release 8.47LTS
Maintained. Older releases are best effort.
Upcoming
Not released yet
LTS
Long-term support branch

App Suite Middleware

8.52.208

Behavioral Changes

SCR-1723

Summary: Java 25: virtual-thread HTTP worker pool and opt-in generational ZGC

Summary: The core middleware now runs on Java 25. The Grizzly HTTP request workers run on virtual threads by default (com.openexchange.http.grizzly.virtualThreadsEnabled=true, fallback to the platform-thread pool by setting it to false) and Compact Object Headers (JEP 519) are enabled. No administrator action is required: G1 remains the default garbage collector, so existing memory sizing is unaffected. Generational ZGC is available as an opt-in alternative via the Helm value javaOpts.zgc (default false). When opting in, size for its native-memory headroom: the load-validated configuration is a 4G heap on a 6G container limit with MALLOC_ARENA_MAX=2 (now a chart default) and adequate CPU; without the arena cap the same workload needs 8G. Too little memory does not surface as an OOM but as failing outbound IMAP/SMTP connections. On hosting billed by RSS, javaOpts.zgcUncommitDelay returns idle heap to the OS sooner than the 300s default. A full-stack load test (50 concurrent users, real Dovecot/Postfix, identical 4G/6G sizing, both error-free) measured ZGC faster than G1 - mean 38 vs 56 ms, p95 106 vs 130 ms, p99 213 vs 796 ms, +47% throughput - at a cgroup peak of ~5.3G vs ~1.3G, the gap being ZGC's eager heap commit rather than GC overhead. Stay on G1 for tight containers, throughput- or batch-bound workloads and CPU-starved pods. The shared worker thread pool defaults change as well: com.openexchange.threadpool.maximumPoolSize from 2147483647 to 2000, com.openexchange.threadpool.workQueue from synchronous to linked, and com.openexchange.threadpool.virtual.maxConcurrency from the fixed 20000 to auto, derived at start-up from the maximum heap size and the active collector and clamped to [512, 20000], tunable via com.openexchange.threadpool.virtual.maxConcurrency.auto.heapFraction (default 0.25) and ...auto.perRequestKB (default 256). Full admin guide: https://documentation.open-xchange.com/8/middleware/administration/garbage_collection_and_memory_sizing.html

8.52.207

Behavioral Changes

SCR-1723

Summary: Java 25: virtual-thread HTTP worker pool and opt-in generational ZGC

Summary: The core middleware now runs on Java 25. The Grizzly HTTP request workers run on virtual threads by default (com.openexchange.http.grizzly.virtualThreadsEnabled=true, fallback to the platform-thread pool by setting it to false) and Compact Object Headers (JEP 519) are enabled. No administrator action is required: G1 remains the default garbage collector, so existing memory sizing is unaffected. Generational ZGC is available as an opt-in alternative via the Helm value javaOpts.zgc (default false). When opting in, size for its native-memory headroom: the load-validated configuration is a 4G heap on a 6G container limit with MALLOC_ARENA_MAX=2 (now a chart default) and adequate CPU; without the arena cap the same workload needs 8G. Too little memory does not surface as an OOM but as failing outbound IMAP/SMTP connections. On hosting billed by RSS, javaOpts.zgcUncommitDelay returns idle heap to the OS sooner than the 300s default. A full-stack load test (50 concurrent users, real Dovecot/Postfix, identical 4G/6G sizing, both error-free) measured ZGC faster than G1 - mean 38 vs 56 ms, p95 106 vs 130 ms, p99 213 vs 796 ms, +47% throughput - at a cgroup peak of ~5.3G vs ~1.3G, the gap being ZGC's eager heap commit rather than GC overhead. Stay on G1 for tight containers, throughput- or batch-bound workloads and CPU-starved pods. The shared worker thread pool defaults change as well: com.openexchange.threadpool.maximumPoolSize from 2147483647 to 2000, com.openexchange.threadpool.workQueue from synchronous to linked, and com.openexchange.threadpool.virtual.maxConcurrency from the fixed 20000 to auto, derived at start-up from the maximum heap size and the active collector and clamped to [512, 20000], tunable via com.openexchange.threadpool.virtual.maxConcurrency.auto.heapFraction (default 0.25) and ...auto.perRequestKB (default 256). Full admin guide: https://documentation.open-xchange.com/8/middleware/administration/garbage_collection_and_memory_sizing.html

8.52.206

3rd Party Libraries/License Change

SCR-1796

Summary: Updated Netty libraries from v4.2.15 to v4.2.16 in bundle io.netty

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

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)

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

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

First step of the HttpClient 4.x (EOL) to 5.x migration (core#544):

  • Added httpclient5 5.6.2, httpcore5 5.4.3 and httpcore5-h2 5.4.3 as target platform bundles (com.openexchange.bundles). The upstream jars ship without OSGi metadata, so OSGi manifests are re-added (versioned exports; optional imports for conscrypt/brotli4j/zstd/commons-compress). Provided additively next to the existing 4.x bundles.
  • Added an HttpClient-5-based twin of the managed HTTP client machinery as com.openexchange.rest.client.httpclient.v5 (service, managed client with hard connect/read timeout watchers, pooling connection manager with monitoring metrics, cookie stores and lenient cookie spec, security route planners and redirect strategies, configuration SPI). The twin service is registered in parallel to the 4.x service so that consuming bundles can migrate individually.
  • Migrated com.openexchange.conference.webhook as the first consumer (blueprint).

The 4.x based service and platform bundles remain untouched until all consumers (incl. dependent repositories) are migrated.

SCR-1786

Summary: Upgraded Apache PDFBox from 2.0.x to 3.0.7

Upgraded the PDF stack used for mail export (com.openexchange.mail.exportpdf.impl) and the target platform:

  • pdfbox/fontbox/xmpbox upgraded from 2.0.27 to 3.0.7 (new companion artifact pdfbox-io)

  • Unused pdfbox-tools and preflight embeds removed (never referenced by code)

  • pdfbox2-layout 1.0.1 has no PDFBox 3 compatible release; its MIT-licensed sources are vendored into the bundle (rst.pdfbox.layout.*) and ported to the PDFBox 3 API

  • Target platform pdfbox/fontbox 2.0.30 upgraded to 3.0.7 (+ pdfbox-io); consumed by openexchange-test (ExportPDFTest)

  • Code migrated to the PDFBox 3 API: Loader.loadPDF instead of PDDocument.load, Standard14Fonts.FontName based font construction, MemoryUsageSetting.streamCache, PDPageContentStream.AppendMode, xmpbox createAndAddPDFAIdentificationSchema

SCR-1785

Summary: Upgraded OpenSAML from 3.4.5 to 5.2.3

Upgraded the SAML stack in com.openexchange.saml from the EOL OpenSAML 3.4.5 to the supported OpenSAML 5.2.3:

  • All opensaml-* artifacts upgraded from 3.4.5 to 5.2.3 (opensaml-core is split into opensaml-core-api/opensaml-core-impl upstream)

  • net.shibboleth.utilities:java-support 7.5.1 replaced by the modular net.shibboleth shared libraries 9.2.3 (shib-support/shib-security/shib-networking/shib-velocity); exported packages move from net.shibboleth.utilities.java.support.* to net.shibboleth.shared.*

  • xmlsec upgraded from 2.3.4 to 3.0.6, metrics-core from 3.1.2 to 4.2.39

  • New embedded transitives httpclient5 5.3.1/httpcore5 5.2.5 (required by the OpenSAML 5 initialization service)

  • Obsolete joda-time usage migrated to java.time.Instant; obsolete Apache Xerces Import-Package entries removed (OpenSAML 5 configures JDK XML parser limits that Xerces does not understand)

  • OpenSAML >= 4.1 is not published to Maven Central; the Shibboleth releases repository is added to the build with content filtering for org.opensaml/net.shibboleth

SCR-1784

Summary: Upgraded Google API/HTTP/OAuth client stack and Firebase Admin SDK

Upgraded the Google client stack (com.google.api.client) and Firebase Admin SDK (com.google.firebase):

  • google-http-client (+ apache-v2/appengine/gson/jackson2/protobuf/xml modules) upgraded from 1.43.3/1.42.3 to 2.1.1
  • google-api-client (+ appengine/gson/jackson2/protobuf/servlet/xml modules) upgraded from 2.2.0 to 2.9.0
  • google-oauth-client (+ appengine/java6 modules) upgraded from 1.34.1 to 1.39.0
  • google-api-services calendar/drive/gmail/people upgraded to current revisions (rev20260614/rev20260624/rev20260525/rev20251117); oauth2 unchanged upstream
  • api-common upgraded from 2.15.0 to 2.65.0
  • grpc-context upgraded from 1.27.2 to 1.70.0 (new companion grpc-api 1.70.0)
  • New embedded transitive: google-auth-library-credentials/google-auth-library-oauth2-http 1.47.0
  • firebase-admin upgraded from 9.2.0 to 9.10.0; its default HTTP transport (ApacheHttp2Transport) requires embedding httpclient5 5.3.1, httpcore5 5.2.4 and httpcore5-h2 5.2.4; nimbus-jose-jwt is consumed from the platform bundle (com.nimbus)

Merged to main via core!5065 (commit c2415d6f1dd).

SCR-1780

Summary: Upgraded Apache CXF to 4.2.2 and Metro JAX-WS runtime to 4.0.5

Upgraded the SOAP stack embedded in the com.openexchange.soap.common bundle:

  • 11 cxf-* libraries upgraded from 4.0.7 to 4.2.2

  • jakarta.xml.ws-api-3.0.1.jar upgraded to jakarta.xml.ws-api-4.0.3.jar

  • jaxws-rt-3.0.2.jar (Metro) upgraded to jaxws-rt-4.0.5.jar

  • saaj-impl-2.0.1.jar upgraded to saaj-impl-3.0.6.jar

  • neethi-3.2.1.jar upgraded to neethi-3.2.2.jar, xmlschema-core-2.3.1.jar to xmlschema-core-2.3.2.jar, gmbal-api-only-4.0.3.jar to gmbal-api-only-4.1.2.jar, mimepull-1.9.15.jar to mimepull-1.11.0.jar, streambuffer-2.0.2.jar to streambuffer-2.1.0.jar

The legacy javax.xml.ws compatibility libraries stay unchanged.

SCR-1775

Summary: Upgraded Spring Framework to 7.0.8 and jOOX to 2.0.1

Upgraded third-party libraries embedded in the com.openexchange.xml bundle:

  • spring-core-6.2.15.jar upgraded to spring-core-7.0.8.jar
  • spring-beans-6.2.15.jar upgraded to spring-beans-7.0.8.jar
  • spring-jcl-6.2.15.jar removed (merged into spring-core in Spring Framework 7)
  • joox-1.5.0.jar upgraded to joox-2.0.1.jar

SCR-1774

Summary: Upgraded Hazelcast library to 5.7.0

Upgraded third-party library embedded in the com.hazelcast bundle:

  • hazelcast-5.3.8.jar upgraded to hazelcast-5.7.0.jar

Note for operators: Hazelcast Open Source does not support rolling upgrades across minor versions. During a deployment upgrade, middleware nodes running 5.7.0 will form a separate cluster from remaining 5.3.8 nodes until the rollout completes; cluster-wide volatile data (e.g. sessions held in Hazelcast maps) follows the usual full-cluster-upgrade semantics.

SCR-1773

Summary: Upgraded OWASP ESAPI library to 2.7.0.0

Upgraded third-party library embedded in the com.openexchange.common bundle:

  • esapi-2.0.1.jar upgraded to esapi-2.7.0.0.jar

Only the org.owasp.esapi.codecs package is consumed by the middleware (HTML entity decoding in com.openexchange.html); the new transitive dependency tree of the unused ESAPI reference implementation (antisamy, batik, httpclient) is excluded from the bundle.

SCR-1772

Summary: Upgraded Box Java SDK to 4.16.4

Upgraded third-party libraries embedded in the com.openexchange.file.storage.boxcom bundle:

  • box-java-sdk-2.54.0.jar upgraded to box-java-sdk-4.16.4.jar (latest release of the classic com.box.sdk API line; the 10.x line is a different, generated SDK with a new API)
  • jose4j-0.5.5.jar upgraded to jose4j-0.9.4.jar
  • zstd-jni-1.5.7-2.jar newly embedded (response decompression support of the SDK)

The SDK now performs HTTP via OkHttp, which is consumed from the com.squareup.okhttp3 platform bundle; that bundle additionally exports the kotlin base package. File thumbnails are retrieved through the file representations endpoint, as the SDK removed the legacy thumbnail API.

SCR-1771

Summary: Upgraded Dropbox Core SDK to 8.0.1

Upgraded third-party library embedded in the com.openexchange.oauth.dropbox bundle:

  • dropbox-core-sdk-3.1.5.jar upgraded to dropbox-core-sdk-8.0.1.jar

SCR-1770

Summary: Upgraded Apache XML-RPC libraries to 6.1.0

Upgraded third-party libraries embedded in middleware bundles:

  • com.openexchange.parallels: xmlrpc-client-5.0.0.jar, xmlrpc-common-5.0.0.jar, xmlrpc-server-5.0.0.jar upgraded to 6.1.0; ws-commons-util-1.0.2.jar upgraded to ws-commons-util-1.1.0.jar
  • com.openexchange.eas.provisioning.action.sms: xmlrpc-client-5.0.0.jar, xmlrpc-common-5.0.0.jar upgraded to 6.1.0; ws-commons-util-1.0.2.jar upgraded to ws-commons-util-1.1.0.jar

SCR-1769

Summary: Upgraded lib-recur library to 0.17.1

Upgraded third-party library embedded in the com.openexchange.chronos.common bundle:

  • lib-recur-0.10.jar upgraded to lib-recur-0.17.1.jar
  • jems2-2.23.1.jar newly embedded (required by lib-recur 0.17)

The recurrence rule expansion engine (org.dmfs.rfc5545.recur) is updated to the latest upstream release. The legacy recurrence-set helper classes that upstream removed in favor of a redesigned API are retained as sources in the bundle, so the iteration behavior of the calendar recurrence service is unchanged (verified by the full recurrence test suite, 50000+ tests).

SCR-1768

Summary: Upgraded ez-vcard library to 0.12.2

Upgraded third-party library embedded in the com.openexchange.contact.vcard.impl bundle:

  • ez-vcard-0.10.6.jar upgraded to ez-vcard-0.12.2.jar

The vCard date mappings were adopted to the library's new java.time-based API. Date properties (BDAY, ANNIVERSARY) are now handled as LocalDate without the former local-timezone adjustment workarounds; the serialized vCard output is unchanged.

SCR-1767

Summary: Upgraded ROME, jaudiotagger, Caffeine, MaxMind GeoIP2 and libphonenumber libraries

Upgraded third-party libraries embedded in middleware bundles:

  • com.openexchange.rss: rome-1.19.0.jar upgraded to rome-2.1.0.jar, rome-utils-1.19.0.jar upgraded to rome-utils-2.1.0.jar (rome-fetcher stays at 1.19.0, no 2.x release exists)
  • com.openexchange.server: jaudiotagger-2.2.5.jar upgraded to jaudiotagger-3.0.1.jar
  • com.openexchange.oauth.provider.impl: caffeine-2.8.5.jar upgraded to caffeine-3.2.4.jar
  • com.openexchange.geolocation.maxmind.binary: geoip2-2.17.0.jar upgraded to geoip2-5.1.0.jar, maxmind-db-2.1.0.jar upgraded to maxmind-db-4.1.0.jar
  • com.openexchange.sms: libphonenumber-8.13.1.jar upgraded to libphonenumber-9.0.34.jar

SCR-1766

Summary: Upgraded webauthn-server-core, reactor-core and zero-allocation-hashing libraries

Upgraded third-party libraries embedded in middleware bundles:

  • com.openexchange.webauthn: webauthn-server-core-2.5.3.jar upgraded to webauthn-server-core-2.9.0.jar, yubico-util-2.5.3.jar upgraded to yubico-util-2.9.0.jar
  • io.lettuce: reactor-core-3.6.6.jar upgraded to reactor-core-3.8.6.jar
  • net.openhft.hashing: zero-allocation-hashing-0.16.jar upgraded to zero-allocation-hashing-2026.0.jar

SCR-1765

Summary: Upgraded BouncyCastle libraries to 1.84 in target platform

Upgraded BouncyCastle libraries in target platform (com.openexchange.bundles):

  • bcmail-jdk18on-1.79.jar upgraded to bcmail-jdk18on-1.84.jar
  • bcpg-jdk18on-1.79.jar upgraded to bcpg-jdk18on-1.84.jar
  • bcpkix-jdk18on-1.79.jar upgraded to bcpkix-jdk18on-1.84.jar
  • bcprov-jdk18on-1.79.jar upgraded to bcprov-jdk18on-1.84.jar
  • bcutil-jdk18on-1.79.jar upgraded to bcutil-jdk18on-1.84.jar

BouncyCastle 1.84 removed the legacy post-quantum algorithm packages org.bouncycastle.pqc.crypto.rainbow, org.bouncycastle.pqc.jcajce.provider.gmss and org.bouncycastle.pqc.jcajce.provider.mceliece; stale (unused) imports of these packages were removed from the com.openexchange.saml bundle manifest. The OpenPGP API change of PGPKeyEncryptionMethodGenerator.generate(...) was adopted in com.openexchange.pgp.core (wire format of generated PKESK packets is unchanged).

SCR-1763

Summary: Upgraded OkHttp to v5.4.0 in com.squareup.okhttp3

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

Upgraded the embedded database migration engine in the encapsulated liquibase.core wrapper bundle:

  • liquibase-core-4.33.0.jar upgraded to liquibase-core-5.0.3.jar
  • opencsv-5.11.2.jar upgraded to opencsv-5.12.0.jar

Liquibase 5.0.x is a major release, but the exported package set and external dependency surface are identical to 4.33.0, so Export-Package/Import-Package stay structurally unchanged. The in-house Liquibase extensions in com.openexchange.database.migration (custom ChangeLogHistoryService, XML changelog parser, preconditions, SLF4J logging) compile and pass their tests against the 5.0.3 SPIs without source changes.

Checksum stability was verified end-to-end against MariaDB: a DATABASECHANGELOG populated with legacy checksums is recognized as already-applied and left untouched (no changeset re-execution), preserving rollback compatibility.

SCR-1755

Summary: Updated Kubernetes Java Client (fabric8) from v7.5.2 to v7.8.0

Updated fabric8 Kubernetes Java Client from v7.5.2 to v7.8.0 (minor version migration) in bundle io.fabric8.kubernetes:

  • kubernetes-client-7.8.0.jar
  • kubernetes-client-api-7.8.0.jar
  • kubernetes-httpclient-jdk-7.8.0.jar
  • kubernetes-model-admissionregistration-7.8.0.jar
  • kubernetes-model-apiextensions-7.8.0.jar
  • kubernetes-model-apps-7.8.0.jar
  • kubernetes-model-autoscaling-7.8.0.jar
  • kubernetes-model-batch-7.8.0.jar
  • kubernetes-model-certificates-7.8.0.jar
  • kubernetes-model-common-7.8.0.jar
  • kubernetes-model-coordination-7.8.0.jar
  • kubernetes-model-core-7.8.0.jar
  • kubernetes-model-discovery-7.8.0.jar
  • kubernetes-model-events-7.8.0.jar
  • kubernetes-model-extensions-7.8.0.jar
  • kubernetes-model-flowcontrol-7.8.0.jar
  • kubernetes-model-gatewayapi-7.8.0.jar
  • kubernetes-model-metrics-7.8.0.jar
  • kubernetes-model-networking-7.8.0.jar
  • kubernetes-model-node-7.8.0.jar
  • kubernetes-model-policy-7.8.0.jar
  • kubernetes-model-rbac-7.8.0.jar
  • kubernetes-model-resource-7.8.0.jar
  • kubernetes-model-scheduling-7.8.0.jar
  • kubernetes-model-storageclass-7.8.0.jar
  • zjsonpatch-7.8.0.jar
  • snakeyaml-engine-3.0.1.jar (upgraded from v2.10)

The generex-1.0.2.jar and automaton-1.11-8.jar libraries were dropped; they are no longer referenced by the Kubernetes client since v7.7.0.

Exported packages follow upstream model changes: io.fabric8.kubernetes.api.model.clusterapi.v1beta1 was replaced by io.fabric8.kubernetes.api.model.clusterapi.core.v1beta1, io.fabric8.kubernetes.api.model.storagemigration.v1alpha1 by io.fabric8.kubernetes.api.model.storagemigration.v1beta1; new exports io.fabric8.kubernetes.api.model.scheduling.v1alpha2 and io.fabric8.kubernetes.api.model.resource.v1.

The bundle now additionally imports org.apache.commons.compress.archivers, org.apache.commons.compress.archivers.tar and org.apache.commons.compress.utils (required by pod upload/copy code paths). Stale imports of okhttp3/okio and SnakeYAML 1.x packages were removed; no code path references them.

SCR-1754

Summary: Migrated S3 file storage to AWS SDK for Java v2

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)

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

Updated Netty libraries from v4.1.132 to v4.2.15 (minor version migration) in bundle io.netty:

  • netty-buffer-4.2.15.Final.jar
  • netty-codec-base-4.2.15.Final.jar (new; codec split in Netty 4.2)
  • netty-codec-compression-4.2.15.Final.jar (new)
  • netty-codec-dns-4.2.15.Final.jar
  • netty-codec-http2-4.2.15.Final.jar
  • netty-codec-http-4.2.15.Final.jar
  • netty-codec-marshalling-4.2.15.Final.jar (new)
  • netty-codec-protobuf-4.2.15.Final.jar (new)
  • netty-codec-socks-4.2.15.Final.jar
  • netty-codec-xml-4.2.15.Final.jar (new)
  • netty-common-4.2.15.Final.jar
  • netty-handler-4.2.15.Final.jar
  • netty-handler-proxy-4.2.15.Final.jar
  • netty-resolver-4.2.15.Final.jar
  • netty-resolver-dns-4.2.15.Final.jar
  • netty-transport-4.2.15.Final.jar
  • netty-transport-native-unix-common-4.2.15.Final.jar
  • netty-transport-classes-epoll-4.2.15.Final.jar
  • netty-transport-native-epoll-4.2.15.Final.jar
  • netty-transport-classes-io_uring-4.2.15.Final.jar (new native transport classes)
  • netty-transport-classes-kqueue-4.2.15.Final.jar
  • netty-transport-native-kqueue-4.2.15.Final.jar
  • netty-tcnative-classes-2.0.80.Final.jar

The netty-codec jar was dropped (empty aggregator in 4.2). Exported package io.netty.handler.ssl.ocsp no longer exists in Netty 4.2; new exports: io.netty.channel.uring plus shaded jctools sub-packages.

Note: Netty 4.2 changes the default ByteBuf allocator from pooled to adaptive. The previous behavior can be restored via system property -Dio.netty.allocator.type=pooled.

Updated Lettuce Redis client from v6.8.2 to v7.6.0 (major version upgrade, requires Netty 4.2) in bundle io.lettuce:

  • lettuce-core-7.6.0.RELEASE.jar
  • redis-authx-core-0.1.1-beta2.jar (new mandatory dependency, MIT license)

Bundle now additionally imports org.slf4j (hard dependency of Lettuce 7.x). Embedded reactor-core-3.6.6.jar and reactive-streams-1.0.4.jar remain unchanged.

SCR-1749

Summary: Upgraded Grizzly to 5.0.2

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)

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

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"

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

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

A foreign-context principal is addressable over the DAV protocols by a qualified principal path; foreign grants are handled consistently in DAV ACL/sharing. Additive (host-context principals unchanged).

  • Qualified principal URLs /principals/users/<id>@<contextId> (resp. groups), via Entity.toFormattedString() (com.openexchange.dav.mixins.PrincipalURL). UserPrincipalCollection / GroupPrincipalCollection parse the qualified leaf and resolve a foreign principal only if the cross-context authority permits a liaison from the session user to the target context (CrossContextAuthorityProvider.isLiaisonPermitted); a disallowed context is reported as 404 (invisible, never confirmed). The foreign principal resource carries a reduced property set — identity + addressing for a user (display name, e-mail, calendar-user-address, resource id), identity only for a group — dropping the context-local navigational properties (calendar / addressbook home sets, group membership) as not meaningful across the context boundary.
  • Folder-sharing invite property: the CalDAV calendar invite (<CS:invite>, com.openexchange.caldav.mixins.Invite) includes foreign-context sharees — each as a context-qualified principal href (/principals/users/<id>@<contextId>) with a display name from the permission's EntityInfo (host-context user/group lookup can't resolve a foreign principal). The base WebDAV folder invite (<D:sharee>, com.openexchange.dav.mixins.Invite) instead omits foreign-context grants — it emits only id-only local principal paths, which can't address a foreign principal (public folders emit no sharees at all).
  • CalDAV: a foreign-context calendar owner/organizer is surfaced via its mail URI only (no bare entity); context is compared alongside the id when matching the acting user.

See the feature documentation for further details.

SCR-1738

Summary: Cross-Context Deputy via Qualified Identifiers (Deputy HTTP API)

The deputy HTTP API can appoint and represent a deputy or grantor in another context. Additive.

  • DeputyPermission.identifier (request) — <id>@<contextId> or mailto:<email>; supersedes userId when present.
  • GrantedDeputyPermission (response) — identifier (deputy) and grantorIdentifier (grantor) as <userId>@<contextId>; the bare userId/grantorId are not meaningful for a foreign entity.
  • GrantedDeputyPermission.entityInfo (response) — pre-resolved entity information (display name, e-mail, ...) for the deputy entity, so a client can render a (possibly foreign-context) deputy it cannot resolve on its own; mirrors the shared-account entityInfo block. Absent for a group deputy; for a foreign entity the numeric entity is omitted and only the qualified identifier is carried.
  • GrantedDeputyPermission.grantorEntityInfo (response; action=reverse) — the counterpart of entityInfo for the granting user, so the deputy can render a (possibly foreign-context) grantor.
  • Available-deputy-modules action: new optional extended=true returns objects with a crossContext flag per module (true only for mail/calendar when the user is in a trust zone and the feature is enabled); the default array form is unchanged.

See the HTTP API documentation and the Deputy permissions documentation for further details.

SCR-1737

Summary: New Read-Only Contact Field Exposing the Cross-Context Qualified Identifier

New read-only contact field surfacing a contact's internal user as a qualified principal identifier, for direct use as a permission identifier.

  • Column 625 (Contact.USER_IDENTIFIER); JSON field user_identifier (ContactFields.USER_IDENTIFIER).
  • Value: <userId>@<contextId> (opaque, round-tripped verbatim). Virtual / read-only, not persisted (no DB change); emitted only when the column is requested and both ids are present. For a foreign entity the numeric INTERNAL_USERID (524) is masked.

See the HTTP API documentation for further details.

SCR-1736

Summary: Folder Permissions Accept and Return Cross-Context Principal Identifiers

A folder permission may address a foreign-context recipient via the long-standing identifier field instead of the numeric entity. Additive.

  • Write: identifier = <id>@<contextId> (e.g. 3@1337) or mailto:<email> (resolved via a PrincipalUriResolver). A foreign principal is admitted only if the cross-context authority permits, else FLD-1053 (PERMISSION_DENIED_CROSS_CONTEXT).
  • Read: identifier is always present (qualified form); the numeric entity is written only for local principals (masked for foreign). Extended folder/file permissions surface a foreign principal via identifier/EntityInfo and do not anonymize it under a guest session.
  • The same identifier semantics are documented on the Drive folder-permission schemas (Drive is not itself a cross-context target).
{ "entity": 42, "bits": 4 }                                // internal (unchanged)
{ "identifier": "3@1337", "bits": 4 }                      // cross-context, by qualified id
{ "identifier": "mailto:bob@partner.example", "bits": 4 }  // by email

See the HTTP API documentation and the feature documentation for further details.

API - REST

SCR-1801

Summary: New Administrative REST Servlet for Querying Free/Busy Data

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

New administrative REST service for cross-context liaison audit + on-demand purge. Base /preliminary/crosscontext/v1; HTTP Basic auth (admin); preliminary. OpenAPI: http-api/rest_api/paths/crosscontext/v1/.

  • GET /inbound/{context} and GET /inbound/{context}/{user} — what a principal received (per-module liaisons, trust zones, mail-share owners).
  • DELETE /inbound/{context}/{user} — purge received access; filters from / owner / module; unconditional operator override (does not consult the authority).
  • GET /outbound/{context}/{user} and DELETE /outbound/{context}/{user} — what a principal granted out, and purge it; filters to / module.

See the REST API documentation and the feature documentation (inbound/outbound audit and on-demand purge) for further details.

API - RMI

SCR-1741

Summary: Cross-Context Deputy in the Admin RMI Provisioning API

The admin deputy provisioning over RMI (com.openexchange.admin.rmi; impl com.openexchange.admin.rmi.impl.OXDeputyPermissions) can appoint/represent a deputy in another context. Additive; an absent / 0 context = same context. A cross-context deputy is admitted only if the authority permits.

Data objects (com.openexchange.admin.rmi.dataobjects):

  • DeputyPermission — qualified Entity entity (id + context).
  • DeputyPermissionDescription — entityContextId (with setEntityContextId / removeEntityContextId / isEntityContextSet flag accessors).
  • Granter — qualified Entity entity; equals / compareTo consider the context.

On top of RMI, the gRPC provisioning layer carries the same cross-context support — generated stubs (com.openexchange.grpc.generated, consumed as a binary artifact) plus DeputyPermissionConverter (com.openexchange.provisioning.grpc.common). In deputy.proto: additive scalar context fields DeputyPermission.entity_context_id, Granter.context_id, DeputyPermissionDescription.entityContextId + EntityContextIdSet (0 = same context); plus the GrantedDeputyPermissions.granted map key retyped map<int32, …> -> map<string, …> (qualified <id>@<contextId>) — the one wire-breaking change (ListReverseDeputyPermissions response). The DeputyPermissionConverter carries the entity context across the boundary; the gRPC server and client implementations delegate to it.

See the Deputy permissions documentation for further details.

API - SOAP

SCR-1798

Summary: Provision per-account spam handler for secondary accounts (functional mailboxes)

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

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-1791

Summary: Guarded loads in Redis cache v2: cache re-inserts that raced an invalidation are rejected

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.

SCR-1759

Summary: Seal proxy registration URLs via ObfuscatorService instead of static DES key

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

A user in one context can grant a user in another context access to a folder, mail folder, or deputy role within one deployment.

  • Deny-by-default trust zones — admitted only if the sharing user's and target context's com.openexchange.crosscontext.trustZones tags intersect; opt-in per deployment (global = legacy anyone-with-anyone).
  • Hard-deny at grant resolution — a foreign identifier resolving to another context is admitted only if the authority permits, else FLD-1053; enforced centrally (folder resolver, deputy service, admin RMI). Same-context / no-authority-registered unaffected.
  • Public read-only — a foreign grantee may receive up to author on a personal/shared calendar folder, but only read-only on a public folder.
  • Admission-only — checked at grant time, never re-checked on read; an admitted grant survives a later zone change until explicitly revoked. No operator switch (com.openexchange.crosscontext.reenforceOnRead removed; CrossContextAuthorityProvider.isReadReenforcementEnabled hard-wired false; dormant code retained).
  • Mail same-server — requires com.openexchange.mail.crossContextPermissions (default false) and, when com.openexchange.mail.crossContextRequireSameServer (default true), the same mail server; an explicit revoke removes the IMAP ACL via best-effort doveadm.
  • Deputy — a revoke/purge revokes the foreign reverse permission (cascading to projected calendar/mail shares; deputy liaisons purged first).

See the feature documentation for further details.

CLT

SCR-1758

Summary: New Command-Line Tool claimfolderadmin to Claim/Elevate a Folder Administrator on Public Folders

New command-line tool claimfolderadmin that grants or elevates a specific user to folder administrator on public folders - the only folder type that permits more than one administrator (FolderObject.PUBLIC; private and shared folders are restricted to a single owner-admin). It targets the case where a deleted user's data was reassigned to a user that cannot log in (e.g. the context administrator): another user can then take over administration of the affected public folders. The operation is additive - existing administrators are kept.

The tool is invoked as follows:

claimfolderadmin -c <contextId> -u <userId>
                 (-f <folderId> | --from-user <sourceUserId>)
                 -A <admin> -P <password>
                 [-p <RMI-Port>] [-s <RMI-Server>]
  • -c/--context - the target context
  • -u/--user - the user that shall become folder administrator
  • -f/--folder - a single public folder to claim
  • --from-user - bulk mode: claim every public folder currently administered by this source user (mutually exclusive with -f)

Authenticates with the context administrator credentials (-A/-P).

The claim operation behaves as follows:

  • Grants full administrative rights plus the folder-admin flag; an existing permission of the user is elevated in place (no duplicate entry). Additive - existing administrators are retained.
  • Only FolderObject.PUBLIC folders are accepted; private/shared folders are rejected (OXFolderExceptionCode.NOT_A_PUBLIC_FOLDER).
  • Bulk mode (--from-user) is scoped to the public folder subtrees - below SYSTEM_PUBLIC_FOLDER_ID (public groupware folders) and SYSTEM_PUBLIC_INFOSTORE_FOLDER_ID (public InfoStore folders); the source user's personal InfoStore home folder and its subfolders are excluded.
  • Idempotent; logs one INFO line per invocation listing the claimed folder identifiers and invalidates the affected folder caches.

Backed by a new RMI service ClaimFolderAdminRMIService registered by the groupware server. For active-active deployments it is site-aware (wrapper SiteAwareClaimFolderAdmin), routing a call to the write-active site owning the target context - plugging into the infrastructure of SCR-1697. Inter-site forwarding uses a new gRPC service ClaimFolderAdminService (client + server) defined in grpc-api/proto_jar/protos/claimfolderadmin.proto.

Documented in documentation/command_line_tools/miscellaneous/claimfolderadmin.md.

SCR-1753

Summary: New command-line tool reassignpersonalfolderowners

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-1803

Summary: New properties for the replication monitor's replica status check

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 (empty SHOW 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.

SCR-1800

Summary: New property to obtain IMAP subscription state from separate LSUB when the \Subscribed attribute of LIST-EXTENDED responses is untrustworthy

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.

SCR-1799

Summary: New property to run the Grizzly engine as WebSocket side-car alongside the Jetty engine

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)

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

Hardening of the Redis connector against stale / orphaned connected clients.

New configuration option:

  • com.openexchange.redis.connection.pool.maxLifetimeSeconds Maximum lifetime in seconds of a pooled Redis connection. Once a connection exceeds this age it is proactively recycled by the connection-pool cleaner as soon as it becomes idle, regardless of usage; this applies to both the shared and the dedicated pool. Acts as defense-in-depth against slowly accumulating or long-lived stale connections that TCP keepalive cannot reap (a live-but-idle connection is never detected as dead). A value of 0 (zero) disables max. lifetime recycling. Default 3600 (one hour). Not reloadable, not config.cascade aware. Package: open-xchange-core.

Behavioral changes (no configuration):

  • Client name: the announced Redis client name now includes the local host / pod name (e.g. Open-Xchange-Redis-Connector-v8.53.0-<host>), so connections become attributable per node via Redis CLIENT LIST. This is what lets operators tell restart orphans (dead pod addresses) apart from live-node connections.
  • Deterministic shutdown: the shared connection pool now closes its connections synchronously on shutdown, so Redis reclaims the clients immediately on a graceful (rolling) restart instead of leaving them as ghosts.

SCR-1788

Summary: Increased defaults for the client-side prepared statement cache (prepStmtCacheSize, prepStmtCacheSqlLimit)

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"

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

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

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

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-1777

Summary: Enable client-side prepared statement caching by default (cachePrepStmts)

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.

SCR-1761

Summary: New Helm value javaOpts.compactObjectHeaders in core-mw chart

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-1760

Summary: Changed behavior of blocking thread pool task submission

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.

SCR-1757

Summary: New property "com.openexchange.mail.wellFormedHtmlTruncateOnRaw"

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

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-1751

Summary: New property com.openexchange.infostore.setPersonalFolderOwnerBelowPersonalInfostore

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).

SCR-1735

Summary: New Configuration Options for Cross-Context Sharing

New properties; all reloadable and config.cascade aware.

  • com.openexchange.crosscontext.trustZones — comma-separated trust-zone tags; a grant is admitted only if the sharing user's and target context's tag sets intersect. Source per-user, target per-context. Default empty (deny); global at server scope = legacy anyone-with-anyone.
  • com.openexchange.crosscontext.tryPromoteGuests — promote an email-only guest permission to a cross-context permission when it resolves to an internal user in another context and the authority admits. Default true.
  • com.openexchange.mail.crossContextRequireSameServer — reject a cross-context mail grant unless the grantee's mailbox is on the same mail server (fails open if indeterminate). Default true.
  • com.openexchange.calendar.crosscontext.enabled — enable the cross-context calendar provider, which surfaces calendars shared from other contexts as ordinary calendar accounts (one account per foreign context, over the HTTP API and CalDAV). Default true.

(Mail master switch com.openexchange.mail.crossContextPermissions, default false, recorded under SCR-1574; also subject to the trust-zone gate.)

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

Database

SCR-1734

Summary: Deputy Storage Table Qualifies the Deputy Entity With Its Context

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

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); index principal (cid, permission_cid, permission_id, fuid).
  • virtualPermission / virtualBackupPermission: PK (cid, tree, user, folderId, entityCid, entity).

Each ALTER rewrites the InnoDB clustered index (slow on large tables). Existing schemas: com.openexchange.groupware.update.tasks.RestructureFolderPermissionPrimaryKeyUpdateTask (idempotent; depends on AddPermissionContextIdToFolderPermissionTableUpdateTask). Fresh schemas: the create-table services above.

See the feature documentation for further details.

SCR-1732

Summary: Added a Permission-Context Column to the Folder-Permission Tables

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_cid
  • virtualPermission, virtualBackupPermission -> entityCid

Fresh schemas: com.openexchange.admin.mysql.CreateOXFolderTables / CreateVirtualFolderTables. Existing schemas: com.openexchange.groupware.update.tasks.AddPermissionContextIdToFolderPermissionTableUpdateTask (idempotent, no deps).

See the feature documentation for further details.

SCR-1731

Summary: Added the "xctx_liaisons" Cross-Context Liaison Registry Table and Create-Table Update Task

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 (DatabaseCleanUpService job, 1/day; prunes orphans, fail-safe).

See the feature documentation for further details.

Packaging/Bundles

SCR-1730

Summary: Added New Bundles for Cross-Context Sharing

Three new OSGi bundles, shipped in open-xchange-core (already in open-xchange-core.psf; no install-list change). Bundle-Version 8, BREE JavaSE-25.

  • com.openexchange.crosscontext — API/SPI bundle (liaison registry, authority provider, principal resolution, outbound-share + cleanup SPIs). No activator.
  • com.openexchange.crosscontext.impl — implementation (RDB storage/registry, trust-zone authority, mailto: resolver, DoveAdm mail source/retractor, reconciler, admin REST). Activator com.openexchange.crosscontext.impl.osgi.CrossContextActivator.
  • com.openexchange.chronos.provider.crosscontext — cross-context calendar provider (account reconciler, iTip conversion, incoming-scheduling listener). Activator com.openexchange.chronos.provider.crosscontext.osgi.CrossContextCalendarProviderActivator.

See the feature documentation for further details.

8.52.0

General

Middleware Image Migrated from Debian to Wolfi OS

Summary: The App Suite Middleware container image now builds on Wolfi OS instead of Debian Bookworm

The App Suite Middleware container image now builds on Wolfi OS instead of Debian Bookworm. The Middleware application itself is unchanged.

What's new
  • Images are signed (cosign) with SLSA v0.2 provenance and ship an SPDX SBOM.
  • CVE patches flow automatically via Renovate.
  • Image is now slightly smaller than with Debian Bookworm.
  • No package manager at runtime, moving closer to distroless.
Breaking Changes to Verify
  1. /etc/ssl/certs/java/cacerts is now 0444 (read-only). Custom truststore hooks doing cp … && keytool -import … must add chmod 0644 between the two steps.
  2. No apt-get / dpkg at runtime. Use kubectl debug or the appsuite-toolkit for in-pod investigation; installing packages live is no longer possible.
  3. MariaDB client is pinned to 11.4 LTS (no Renovate auto-bump). It is wire-compatible with MySQL 5.5+ and MariaDB 10.x+ servers.
  4. Implicit Debian tools are no longer present: which, diff, xz, wget, and the hostname binary. Customer scripts using these need POSIX alternatives (command -v for which, $HOSTNAME for hostname).
  5. The Java vendor changes from Eclipse Temurin to Wolfi OpenJDK 25 (same upstream source, identical bytecode/API). Binaries like jmap, jstack, jcmd, jstat, jinfo, and jps are no longer bundled with the runtime image. For heap dumps, thread dumps, mysqldump, and other diagnostics against a running pod, use the appsuite-toolkit which provides these operations via command-line tools or ephemeral debug container attached alongside the target pod.
  6. mysql is now a symlink to mariadb, which prints a one-time deprecation warning at invocation.
Action Items for Operators
  • Smoke-test on a non-production cluster with your existing Helm values.
  • Verify any custom hook scripts (truststore imports, CA bundles, custom CLTs) against the new image.
Prev
Important Changes
Next
OX Documents