This is an automated email from the ASF dual-hosted git repository. robertlazarski pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git
commit 69e7eb53495c377f384c924f9a234db2ae4d4b70 Author: Robert Lazarski <[email protected]> AuthorDate: Sun Apr 5 16:19:07 2026 -1000 Wire axis2-openapi module into springbootdemo WildFly sample - Register OpenApiServlet directly in Axis2WebAppInitializer at /openapi.json, /openapi.yaml, /swagger-ui — bypasses Spring MVC DispatcherServlet which is not wired in this WAR deployment - Add openapi-2.0.1-SNAPSHOT.mar to WEB-INF/modules via antrun so AxisServlet can engage the openapi module from axis2.xml - Bypass JWT auth and POST-only filter for OpenAPI GET requests in JWTAuthenticationFilter.requiresAuthentication() and HTTPPostOnlyRejectionFilter.doFilterInternal() - Add @Order(2) OpenAPI security filter chain in Axis2Application to pass OpenAPI paths through without authentication - Apply all security filter fixes to springbootdemo-tomcat11 as well Tested on WildFly 39 + OpenJDK 25: all three endpoints return 200, /openapi.json serves full OpenAPI 3.0.1 JSON, /swagger-ui returns Swagger UI HTML. Existing /services/* JWT-protected endpoints continue to require authentication. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --- .../userguide/springboot/Axis2Application.java | 2 +- .../webservices/HTTPPostOnlyRejectionFilter.java | 7 ++ .../webservices/JWTAuthenticationFilter.java | 4 ++ .../userguide/src/userguide/springbootdemo/pom.xml | 8 +++ .../userguide/springboot/Axis2Application.java | 2 +- .../configuration/Axis2WebAppInitializer.java | 59 +++++++++------- .../springboot/configuration/OpenApiServlet.java | 81 ++++++++++++++++++++++ .../webservices/HTTPPostOnlyRejectionFilter.java | 7 ++ .../webservices/JWTAuthenticationFilter.java | 4 ++ 9 files changed, 147 insertions(+), 27 deletions(-) diff --git a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/Axis2Application.java b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/Axis2Application.java index 838d1bf3b6..bb4b5fe487 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/Axis2Application.java +++ b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/Axis2Application.java @@ -355,7 +355,7 @@ public class Axis2Application extends SpringBootServletInitializer { public boolean matches(HttpServletRequest request) { String uri = request.getRequestURI(); for (String path : OPENAPI_PATHS) { - if (uri.equals(path) || uri.startsWith(path + "/")) { + if (uri.endsWith(path) || uri.contains(path + "/")) { return true; } } diff --git a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java index ba74dbc1e4..f2524f6d4a 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java +++ b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java @@ -55,6 +55,13 @@ public class HTTPPostOnlyRejectionFilter extends OncePerRequestFilter { logger.trace(logPrefix + "starting ... "); + String uri = request.getRequestURI(); + boolean isOpenApiPath = uri.endsWith("/openapi.json") || uri.endsWith("/openapi.yaml") || uri.endsWith("/swagger-ui"); + if (isOpenApiPath) { + filterChain.doFilter(request, response); + return; + } + if (!request.getMethod().equals("POST")) { String ip = "unknown"; diff --git a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java index 4b6e818a9a..59448a68a8 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java +++ b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java @@ -55,6 +55,10 @@ public class JWTAuthenticationFilter extends AbstractAuthenticationProcessingFil @Override protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) { + String uri = request.getRequestURI(); + if (uri.endsWith("/openapi.json") || uri.endsWith("/openapi.yaml") || uri.endsWith("/swagger-ui")) { + return false; // OpenAPI documentation endpoints are public + } return true; } diff --git a/modules/samples/userguide/src/userguide/springbootdemo/pom.xml b/modules/samples/userguide/src/userguide/springbootdemo/pom.xml index c1de1b099e..4184fa663d 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo/pom.xml +++ b/modules/samples/userguide/src/userguide/springbootdemo/pom.xml @@ -370,6 +370,10 @@ <include name="axis2.xml"/> </fileset> </copy> + <!-- Create openapi module archive for WEB-INF/modules --> + <mkdir dir="${project.build.directory}/deploy/axis2-json-api.war/WEB-INF/modules"/> + <copy file="${settings.localRepository}/org/apache/axis2/axis2-openapi/2.0.1-SNAPSHOT/axis2-openapi-2.0.1-SNAPSHOT.jar" + tofile="${project.build.directory}/deploy/axis2-json-api.war/WEB-INF/modules/openapi-2.0.1-SNAPSHOT.mar"/> <unzip src="${project.build.directory}/axis2-json-api-0.0.1-SNAPSHOT.war" dest="${project.build.directory}/exploded"/> <jar jarfile="${project.build.directory}/exploded/WEB-INF/services/Login.aar"> <metainf file="resources-axis2/login_resources/services.xml"/> @@ -385,6 +389,10 @@ <include name="axis2.xml"/> </fileset> </copy> + <!-- Create openapi module archive for exploded WEB-INF/modules --> + <mkdir dir="${project.build.directory}/exploded/WEB-INF/modules"/> + <copy file="${settings.localRepository}/org/apache/axis2/axis2-openapi/2.0.1-SNAPSHOT/axis2-openapi-2.0.1-SNAPSHOT.jar" + tofile="${project.build.directory}/exploded/WEB-INF/modules/openapi-2.0.1-SNAPSHOT.mar"/> </target> </configuration> <goals> diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java index c6e442891c..2bb756381a 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java +++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java @@ -349,7 +349,7 @@ public class Axis2Application extends SpringBootServletInitializer { public boolean matches(HttpServletRequest request) { String uri = request.getRequestURI(); for (String path : OPENAPI_PATHS) { - if (uri.equals(path) || uri.startsWith(path + "/")) { + if (uri.endsWith(path) || uri.contains(path + "/")) { return true; } } diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java index 38e998b5d5..03dfa46bd3 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java +++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java @@ -18,13 +18,13 @@ * under the License. */ package userguide.springboot.configuration; - + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.axis2.transport.http.AxisServlet; import org.springframework.boot.web.servlet.ServletContextInitializer; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.core.annotation.Order; import org.springframework.beans.factory.annotation.Autowired; @@ -33,40 +33,49 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; -import jakarta.servlet.ServletContext; -import jakarta.servlet.ServletRegistration; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletRegistration; + +import java.util.Set; -import java.util.Set; - @Configuration @Order(4) -public class Axis2WebAppInitializer implements ServletContextInitializer { - - private static final Logger logger = LogManager.getLogger(Axis2WebAppInitializer.class); - private static final String SERVICES_MAPPING = "/services/*"; - - @Override - public void onStartup(ServletContext container) { +public class Axis2WebAppInitializer implements ServletContextInitializer { + + private static final Logger logger = LogManager.getLogger(Axis2WebAppInitializer.class); + private static final String SERVICES_MAPPING = "/services/*"; + + @Override + public void onStartup(ServletContext container) { logger.warn("inside onStartup() ..."); - // Create the 'root' Spring application context - AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); - - addAxis2Servlet(container, ctx); + // Create the 'root' Spring application context + AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); + + addAxis2Servlet(container, ctx); + addOpenApiServlet(container); logger.warn("onStartup() completed ..."); } - - private void addAxis2Servlet(ServletContext container, AnnotationConfigWebApplicationContext ctx) { + + private void addAxis2Servlet(ServletContext container, AnnotationConfigWebApplicationContext ctx) { ServletRegistration.Dynamic dispatcher = container.addServlet( "AxisServlet", new AxisServlet()); dispatcher.setLoadOnStartup(1); Set<String> mappingConflicts = dispatcher.addMapping(SERVICES_MAPPING); - if (!mappingConflicts.isEmpty()) { - for (String s : mappingConflicts) { - logger.error("Mapping conflict: " + s); - } - throw new IllegalStateException("'AxisServlet' could not be mapped to '" + SERVICES_MAPPING + "'"); + if (!mappingConflicts.isEmpty()) { + for (String s : mappingConflicts) { + logger.error("Mapping conflict: " + s); + } + throw new IllegalStateException("'AxisServlet' could not be mapped to '" + SERVICES_MAPPING + "'"); } } + private void addOpenApiServlet(ServletContext container) { + ServletRegistration.Dynamic openApi = container.addServlet( + "OpenApiServlet", new OpenApiServlet()); + openApi.setLoadOnStartup(2); + openApi.addMapping("/openapi.json", "/openapi.yaml", "/swagger-ui"); + logger.warn("OpenApiServlet registered at /openapi.json, /openapi.yaml, /swagger-ui"); + } + } diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/OpenApiServlet.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/OpenApiServlet.java new file mode 100644 index 0000000000..2eccd5aed7 --- /dev/null +++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/OpenApiServlet.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package userguide.springboot.configuration; + +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.axis2.context.ConfigurationContext; +import org.apache.axis2.openapi.OpenApiModule; +import org.apache.axis2.openapi.SwaggerUIHandler; +import org.apache.axis2.transport.http.AxisServlet; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.IOException; + +/** + * Servlet that serves OpenAPI documentation endpoints by delegating to + * the Axis2 OpenAPI module's SwaggerUIHandler. + * + * Registered directly in Axis2WebAppInitializer at: + * /openapi.json - OpenAPI 3.0.1 specification (JSON) + * /openapi.yaml - OpenAPI 3.0.1 specification (YAML) + * /swagger-ui - Interactive Swagger UI documentation + */ +public class OpenApiServlet extends HttpServlet { + + private static final Log log = LogFactory.getLog(OpenApiServlet.class); + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + String uri = request.getRequestURI(); + log.info("OpenApiServlet.doGet() called for URI: " + uri); + + ConfigurationContext configContext = (ConfigurationContext) + getServletContext().getAttribute(AxisServlet.CONFIGURATION_CONTEXT); + if (configContext == null) { + log.warn("AxisServlet ConfigurationContext not found in ServletContext"); + response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "OpenAPI module not available"); + return; + } + + SwaggerUIHandler handler = OpenApiModule.getSwaggerUIHandler(configContext); + if (handler == null) { + log.warn("OpenAPI SwaggerUIHandler not found — ensure openapi module is in WEB-INF/modules"); + response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "OpenAPI module not initialized"); + return; + } + + try { + if (uri.endsWith("/openapi.json")) { + handler.handleOpenApiJsonRequest(request, response); + } else if (uri.endsWith("/openapi.yaml")) { + handler.handleOpenApiYamlRequest(request, response); + } else if (uri.contains("/swagger-ui")) { + handler.handleSwaggerUIRequest(request, response); + } else { + response.sendError(HttpServletResponse.SC_NOT_FOUND); + } + } catch (Exception e) { + log.error("OpenApiServlet error handling " + uri + ": " + e.getMessage(), e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + } +} diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java index ba74dbc1e4..f2524f6d4a 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java +++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java @@ -55,6 +55,13 @@ public class HTTPPostOnlyRejectionFilter extends OncePerRequestFilter { logger.trace(logPrefix + "starting ... "); + String uri = request.getRequestURI(); + boolean isOpenApiPath = uri.endsWith("/openapi.json") || uri.endsWith("/openapi.yaml") || uri.endsWith("/swagger-ui"); + if (isOpenApiPath) { + filterChain.doFilter(request, response); + return; + } + if (!request.getMethod().equals("POST")) { String ip = "unknown"; diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java index 4b6e818a9a..59448a68a8 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java +++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java @@ -55,6 +55,10 @@ public class JWTAuthenticationFilter extends AbstractAuthenticationProcessingFil @Override protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) { + String uri = request.getRequestURI(); + if (uri.endsWith("/openapi.json") || uri.endsWith("/openapi.yaml") || uri.endsWith("/swagger-ui")) { + return false; // OpenAPI documentation endpoints are public + } return true; }
