Apache Axis2 2.0.2 Release Notes

Upgrading from 2.0.1

Everything a working 2.0.1 deployment may have to change, in one place. The reasoning for each is further down; this is the checklist.

Defaults that now refuse what they previously allowed. Each is a one-line opt-out in axis2.xml if a deployment genuinely needs the old behaviour.

Change Restore the old behaviour with
Decoupled WS-Addressing responses are refused (AXIS2-6108) <parameter name="allowNonAnonymousResponseEndpoints">true</parameter>
Service dispatch from the SOAP body namespace is off <parameter name="allowContentBasedServiceDispatch">true</parameter>
Admin console ships with empty credentials, so it is disabled set userName and password in your own axis2.xml

The WS-Addressing change is the one most likely to be felt: any client using a non-anonymous ReplyTo or FaultTo stops working until the parameter is set. Deployments that re-enable it should also set httpFrontendHostUrl, because the generated reply address otherwise defaults to the local machine's IP. In this project's own test suite the change touched 17 of 244 integration tests, all decoupled-response cases, and opting those in was the migration – expect the same shape of work.

New ceilings. Requests larger than these are now rejected rather than allocated. Raise them if a deployment legitimately handles bigger messages: multipartMaxRequestSize, multipartMaxFileSize, formUrlEncodedMaxRequestSize, mtomMaxRequestSize, soapMaxRequestSize, and for multiref org.apache.axis2.databinding.multiref.maxDepth.

Classpath and packaging changes. These affect builds and WAR deployments rather than configuration:

  • axis2-spring no longer brings Spring with it. Applications that inherit spring-boot-starter-parent or import spring-boot-dependencies are unaffected – their dependency management already decided the Spring version. Anyone depending on axis2-spring without Spring Boot's dependency management must now declare spring-core, spring-beans, spring-context and spring-web themselves.
  • The JMS and mail transports are no longer bundled in axis2.war. Both remain in lib/ of the binary distribution, so a standalone server is unaffected; a WAR deployment that uses either now adds the transport jar to WEB-INF/lib.
  • jibx is no longer a valid -d value for wsdl2java. JiBX was removed in 2.0.1; the option had survived in the tool's help text without a backing implementation.

Metadata exposure. exposeServiceMetadata is now honoured on every anonymous metadata route rather than only the ?wsdl/?xsd queries, and a service with it disabled is answered as though it were not deployed. If you relied on WS-MEX, the /services/ listing, the ping module or the .xsd/.wsdl file routes reaching a service that had metadata exposure turned off, they no longer will.

Distribution Changes

  • axis2-spring no longer exports Spring to its consumers. Its spring-core, spring-beans, spring-context and spring-web dependencies are now provided rather than compile. The module is an integration layer: the application already has Spring and decides its version. As compile-scope dependencies they were transitive, so a consumer running an older Spring who did not import the Spring Boot BOM silently got this build's Spring on the classpath beside their own. Applications that inherit spring-boot-starter-parent or import spring-boot-dependencies were never affected – dependency management already overrode the transitive version – and are unaffected now. Anyone depending on axis2-spring without Spring Boot's dependency management must declare their own Spring dependencies, which is the intent.

  • Five stray Spring jars dropped from axis2.war and the binary distribution. spring-beans, spring-context, spring-core and spring-web have always been excluded on purpose – a deployment using the Spring integration supplies its own Spring. Spring 7 moved spring-aop, spring-expression, micrometer-observation, micrometer-commons and jspecify behind spring-context and spring-core, and the exclusion lists were never updated, so ~870 KB of Spring fragments shipped that could not work without the four jars deliberately left out. Axis2's own axis2-spring is unchanged and still shipped.

  • google-java-format replaced, dropping ~5.9 MB from the WAR. Codegen tidied its generated Java with google-java-format, a full parse-and-reflow formatter that brought guava and a shaded javac with it – about 6 MB shipped in every axis2.war to format machine-generated code that a template had already laid out. PrettyPrinter now re-indents with no dependencies. It rewrites leading whitespace and nothing else: it does not reflow lines, reorder imports or alter a character the compiler can see, so the worst it can do is indent badly rather than change what generated code means. Braces inside string literals, character literals and comments are not counted, and text blocks are reproduced verbatim because their leading whitespace is part of the string. A formatting failure now leaves the generated file untouched – the previous code deleted the source before renaming the formatted copy over it, so a failure destroyed it. axis2.war goes from 36 MB to 30 MB across this and the JMS, mail and Spring changes above. Guava is therefore no longer in lib/ or WEB-INF/lib; modules that need it at runtime must ship their own – Rampart 2.0.0 does, because OpenSAML and WSS4J require it.

  • The mail transport is no longer bundled in axis2.war either. Same reasoning as JMS: no default axis2.xml enables a mailto listener or sender, and the module is deprecated for removal in 2.0.3. It remains in lib/ of the binary distribution. Note that angus-mail and jakarta.mail-api stay in the WAR and are not mail transport baggage: jakarta.mail-api carries the MimeBodyPart, MimePartDataSource, InternetHeaders and ByteArrayDataSource classes that JAX-WS attachment handling uses, and angus-mail supplies the META-INF/services/jakarta.mail.util.StreamProvider implementation those classes need at runtime. Removing either would break MTOM and SwA, not the mail transport.

  • The JMS transport is no longer bundled in axis2.war. axis2-transport-jms and jakarta.jms-api shipped in every WAR while no default axis2.xml enables a JMS listener or sender, so every deployment carried the transport – and its JNDI lookup code – without asking for it. It was never usable as shipped in any case: jakarta.jms-api is an API with no provider, so enabling JMS always required adding a broker client. The module is unchanged, remains a supported transport, and is still in lib/ of the binary distribution, so a standalone server is unaffected. A WAR deployment that uses JMS now adds axis2-transport-jms to WEB-INF/lib alongside the broker client it already had to add.

  • The dynamicclient sample is removed from the source distribution. It was never part of the build, and its modules declared a parent version that did not match their own aggregator, so it could not be built. Its WSDL 2.0 client also depended on WSDL 2.0 support that is no longer documented. ServiceClient can still be constructed from a WSDL URL; modules/samples/jaxws-addressbook covers the JAX-WS Dispatch client.

  • More unrunnable samples are removed. yahoojsonsearch and yahoorestsearch called Yahoo search APIs that were shut down in 2011, and googlespellcheck called a Google SOAP API retired in 2009; the two Yahoo samples were still in the binary distribution. jaxws-dynamic was shipped with no build file and an empty README, and book depended on 1.8.0 snapshots and was never built. Three Maven samples whose run instructions could not work are removed as well: transport/https-sample ran on the Jetty 6 plugin, which cannot host a Jakarta webapp; java_first_jaxws was set up for a javax-based Cargo container; and transport/jms-sample had no client.

  • The ant-built samples in the binary distribution build again. Since 2.0.1 the binary distribution has placed samples under modules/samples/, but most sample build.xml files still located AXIS2_HOME two directories up, so ant failed looking for modules/lib. They now resolve AXIS2_HOME correctly from AXIS2_HOME/modules/samples/<sample>, and servicelifecycle, which still used a builder class removed in Axiom 2.0, compiles again.

Deprecated for Removal

  • The mail transport (axis2-transport-mail) is deprecated and is planned for removal in 2.0.3. SOAP over SMTP was specified and profiled, but a request/response exchange that blocks a caller thread on a mailbox poll saw very little use even when SOAP was at its most popular, and it shows: no functional change has been made to this module in over a decade, and every commit touching it since 2015 is either a project-wide sweep (the jakarta rename, the SecurityManager removal, a package move) or a test-dependency bump.

    It is not enabled by any default axis2.xml, and as of this release it is no longer bundled in axis2.war either – it remains in lib/ of the binary distribution for anyone who configures it. Its correlation of responses to requests by In-Reply-To (SynchronousCallback and the callback table in AbstractTransportListener) is the only such mechanism in the tree and is used by nothing else; the module's own source carries long-standing FIXME comments saying that machinery does not belong where it sits.

    If you use the mail transport, please say so on the dev list – concrete usage is what would keep it. Otherwise plan to move to an HTTP transport before 2.0.3. Nothing is removed in 2.0.2 and the module continues to work in this release.

Security Hardening

Several defaults changed in this release. Each one closes a surface an unauthenticated caller could reach, and each is listed here with what to set if a deployment genuinely needs the previous behaviour. The full reasoning for each is in SECURITY.md.

  • No default admin console credentials. The published axis2-webapp WAR and the axis2_default.xml inside axis2-kernel.jar shipped admin/axis2 as the /axis2-admin login. That console can upload services, and so execute code. Both now ship empty, which leaves the console disabled: the login rejects empty credentials before comparing, so no request can authenticate until an operator sets both userName and password in their own axis2.xml. Deployments that relied on the default login must now set one explicitly.

  • Service dispatch from the message body is opt-in. The inflow order is Transport, Addressing, Security, PreDispatch, Dispatch, so a service selected during Dispatch is selected after the Security phase has already run — against no service, because none was bound yet — and Security is not revisited. A request whose URI names no service could therefore pick the service from the namespace of the SOAP body's first element, reaching a service whose engaged security modules never ran. allowContentBasedServiceDispatch now defaults to false. Dispatch by request URI, SOAPAction and WS-Addressing is unaffected. Set it to true only if services are genuinely addressed by body namespace, and not alongside per-service security modules.

  • Decoupled WS-Addressing responses are refused by default. A non-anonymous wsa:ReplyTo or wsa:FaultTo makes the server open a connection to an address the caller chose. allowNonAnonymousResponseEndpoints now defaults to false; replies and faults travel back down the inbound connection. Deployments that use decoupled responses — separate-listener “Dual” clients, or a third-party callback endpoint — set it to true, and should also set httpFrontendHostUrl so the generated reply address is the real external URL. With the feature enabled, allowedResponseEndpointSchemes permits HTTPS only, the destination is screened at both the header-parsing and transport-selection layers, and redirects are not followed over either the HTTP or the HTTP/2 sender. Where jms is among the permitted schemes, a reply endpoint may name a destination but no longer supply the JNDI environment used to resolve it: a java.naming.* parameter on a reply address is refused, since it would let the caller choose which broker the server connects to. Deployments replying through a particular provider name it in their own transport configuration.

  • JMS target addresses are screened more precisely. A JMS address becomes JNDI lookups, and JNDI resolves a name carrying a remote naming scheme (ldap:, rmi:, iiop:, corbaname:, dns: and friends) through that scheme's URL context factory, which can fetch and deserialise a remote object. Those schemes are refused in the destination name, the reply destination and the JNDI provider URL. This replaces a guard that searched the whole address for those words as substrings and so refused ordinary destinations whose names contained one: a queue called alarming contains “RMI”, dns-events contains “DNS”. Such names now work again.

  • Multiref resolution is bounded. SOAP multiref references were resolved with no cycle check and no expansion budget, on the anonymous RPC/POJO receiver path. A reference leading back on itself recursed until the stack ended, and a reference graph with no cycle at all could still double at every level – an entity-expansion bomb built from well-formed XML that no parser limit objects to, ending in OutOfMemoryError. Cyclic element references are now refused, nesting depth and total work are bounded, and the cost of copying a referenced element is charged before the copy is made. A cyclic object graph, which SOAP encoding permits and Axis2 has always accepted, still deserializes. The limits are org.apache.axis2.databinding.multiref.maxDepth (64), maxResolutions (5000) and maxExpandedNodes (50000); -1 for unbounded.

  • Request bodies are bounded. The multipart/form-data and application/x-www-form-urlencoded builders read the transport stream directly, so a servlet container's post-size limit never saw the body. multipartMaxRequestSize and multipartMaxFileSize (100 MB), formUrlEncodedMaxRequestSize (2 MB), mtomMaxRequestSize (100 MB, covering the whole multipart/related body and so MTOM and SwA), soapMaxRequestSize (100 MB, a plain SOAP or POX body) and jsonMaxRequestSize (100 MB, every JSON builder including the Gson, Moshi and HTTP/2 variants) now bound them; -1 restores the previous unbounded behaviour, and any may be set per service. All the stream-reading builders are covered, not only the form ones: the caller picks the builder by choosing the Content-Type, so bounding some of them bounds none. The ceilings are enforced against bytes actually read, so a chunked body is bounded on the same terms as a declared one. Multipart temporary files are deleted rather than accumulating.

  • exposeServiceMetadata is honoured uniformly. Every anonymous metadata route now respects it: the ?wsdl, ?wsdl2 and ?xsd queries as before, plus the .xsd/.wsdl file routes on both the servlet and standalone HTTP paths, the named-WSDL route, the OpenAPI/Swagger/MCP generators, the /services/ listing on both render paths, WS-MEX GetMetadata, and the ping module's service-level ping. A service with exposure disabled is skipped rather than refused, so it stays indistinguishable from one that is not deployed – the ?wsdl, ?wsdl2, ?xsd and ?policy routes used to answer 403 for a hidden service where an absent one gets 404, which told an anonymous caller which service names exist; both now answer 404 with the same body. If you relied on a hidden service still appearing in the listing, in a WS-MEX response or in a ping response, it no longer will; set exposeServiceMetadata to true on that service.

  • The ?xsd= route serves only schema and WSDL documents. It reached a service's packaged META-INF with the request's value, so ?xsd=services.xml returned the service descriptor – which names keystores and password-callback classes. Only .xsd and .wsdl names that stay inside META-INF are served now, enforced inside the shared helper so all three callers inherit it.

  • Generated output cannot be written outside the output directory. Code generation derives file names from the document it was handed, and a wsdl:service name reached the shared file sink verbatim – a QName localPart is not required to be an NCName, so separators and .. survived. A WSDL naming its service ../../../src/main/resources/api had the tool write its re-serialized WSDL over a project's real contract file. The sink now refuses a name that resolves outside the output root.

  • Schema values are escaped before they reach generated source. Element and attribute default and fixed values, enumeration facets and the numeric range facets were copied out of the schema into generated Java and C inside string literals with no escaping, so a value carrying a quote closed its literal and the remainder became code in a class-level initializer – which runs when the generated bean class loads, on the build machine and in the shipped application. All of these are escaped now, as the pattern facet already was. QName enumerations are unaffected: the argument split the compiler inserts deliberately is preserved.

  • Every WSDL-loading path is screened, not just the client-side one. wsdl4j parses with its own unhardened parser and fetches imports itself, so a DOCTYPE in a WSDL – or in anything it imports – was an XXE in whichever JVM read it. Only the client-side path was screened. The JAX-WS loader, the runtime reload wrapper, the deployment builder's resolver path and the WSDL2Java entry point now screen too, via a locator that refuses a DOCTYPE without changing where documents may be loaded from: a delegate locator keeps its own catalog or archive resolution, and a bare relative path still works.

  • The schema compiler no longer trusts the schema it is compiling. XSD2Java and the axis2-xsd2java-maven-plugin exist to consume contracts written elsewhere, but parsed them with no XXE hardening and dereferenced xs:include/xs:import locations with whatever scheme they named – so a schema handed to a developer could read local files, exfiltrate them through an external entity, or make the build fetch internal URLs. DOCTYPE and external entities are now refused, and include/import locations resolve from the filesystem only. Sibling schema files, the ordinary case, are unaffected. A build that genuinely resolves schemas over the network passes -asl to the CLI or sets <allowAbsoluteSchemaLocations>true</allowAbsoluteSchemaLocations> on the plugin.

  • Context deserialization: a documented allowlist that never existed is now described accurately, and what can be enforced is. SECURITY.md claimed three times that SafeObjectInputStream restricts deserialization to known Axis2 context classes. It does not, and cannot: the feature exists to carry application objects – SelfManagedDataHolder holds whatever a service put there, and a Parameter value may be any serializable object – so such a list would refuse the data it is for. The streams Axis2 creates now refuse dynamic proxies (org.apache.axis2.context.externalize.allowProxies=true to override), and org.apache.axis2.context.externalize.serialFilter accepts a JEP 290 pattern for an integrator who does know their own types. No Axis2 path feeds these streams from the network; if you persist or replicate contexts, restrict the stream you own.

  • Swagger UI scripts are integrity-pinned. The page loads swagger-ui from a CDN at a pinned version, which says which release to ask for but not that what came back is that release – and the page is built to drive authenticated API calls. The script tags now carry Subresource Integrity hashes and crossorigin="anonymous". The hashes are version-specific, so a deployment pinning a different Swagger UI version supplies its own with openapi.swaggerUi.integrity.bundle and openapi.swaggerUi.integrity.standalonePreset; without them the page still renders and a warning says integrity is not being enforced.

  • Unexpected-error faults no longer name the exception class. An otherwise unhandled error produced a fault reason of fully.qualified.Class: message whatever sendStacktraceDetailsWithFaults was set to, and since that catch-all serves every request the servlet handles, it applied to JSON and REST responses as much as to SOAP faults. The reason is now generic unless details are enabled. The error is logged with its stack as before.

  • WSDL2Java no longer lets a remote server retarget its own WSDL fetch. The tool probes an http location for a redirect before parsing, and took the Location header from any response, unresolved and unconstrained: a stray header on a 200 redirected it, a relative target was used as given, and Location: file:///etc/passwd pointed the parse at the developer's filesystem. A redirect is now followed only from a 3xx status, only to http or https, and a relative target resolves against the document requested; anything else stops code generation instead of silently parsing something else. Connect and read timeouts are applied and configurable.

  • Packaged schema and WSDL documents are served only from the requesting service's own archive. AxisService.printXSD and printWSDL2 – the ?xsd= and ?wsdl2= queries – looked a requested name up with getResourceAsStream, which delegates parent-first, so an anonymous caller could read any META-INF/*.xsd or *.wsdl from jars anywhere on the webapp or container classpath and fingerprint what was deployed. The file routes had been fixed for this once (AXIS2-5846); the query routes had not. Both rules – schemas and WSDLs only, own archive only – now live in one kernel helper, MetaInfResources. A service whose classloader is not a URLClassLoader cannot serve this route at all; deployed archives are unaffected.

  • The absolute-schemaLocation guard no longer fails open on malformed input. WSDLToAxisServiceBuilder's default schema resolver classified locations with java.net.URI and ignored URISyntaxException. A location URI rejects but java.net.URL accepts – one containing a space, |, {, }, ^ or a backslash – was therefore never classified and was resolved as though relative, fetching the remote schema the guard exists to refuse. Classification is textual now. Relative names that URI also rejects still resolve.

  • httpFrontendHostUrl is documented as a requirement, not a convenience. Without it (or an explicit servlet-transport port), the port advertised in generated WSDL comes from the first request's Host header after startup and is kept for the life of the process. See item 14 of SECURITY.md; this is a configuration note, not a code change.

  • Two threat-model claims made true, and their limits stated. The document said every parser factory the framework creates disables DTDs and external entities, and that the AAR/WAR resolvers block file: resolution. Neither held. The SAAJ and JAX-WS conversions now use the hardened factory (XMLUtils.toDOM, SAAJUtil.toDOM, SOAPBodyImpl, LogicalMessageImpl, JAXWSRIWSDLGenerator), and file: is refused by the deployment resolvers – which mattered in one of the four, where an absolute file: import had been reaching the filesystem. SECURITY.md now also names what is not covered: the build-time codegen factories, the deliberate hbm.xml DTD exception, and the TransformerFactory instances.

  • OpenAPI and Swagger UI output. Request-controlled values are validated and encoded for the context they are written into, the served page carries a Content-Security-Policy with a per-response script nonce, and the published servers[].url is relative rather than derived from the request Host. openapi.serverBaseUrl pins an absolute URL where a deployment needs one.

  • JSON field filtering only narrows a response. The ?fields= selector read fields by reflection, so it could name one the serializer never writes: the synthetic this$0 of a non-static inner class, which returned the enclosing object, or with Moshi a field marked @Json(ignore = true). Those fields are now skipped at the top level and in dot paths alike, so a filtered response holds only fields the unfiltered one already contains.

      Release Notes - Axis2 - Version 2.0.2
    

Task

  • [AXIS2-6107] - Remove vestigial context externalization code (SafeObjectInputStream and readExternal)
  • [AXIS2-6108] - WS-Addressing decoupled responses are refused by default from 2.0.2