Skip to content

Commit 69e7eb5

Browse files
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 <noreply@anthropic.com>
1 parent 9fee3fc commit 69e7eb5

9 files changed

Lines changed: 147 additions & 27 deletions

File tree

modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/Axis2Application.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ class OpenApiRequestMatcher implements RequestMatcher {
355355
public boolean matches(HttpServletRequest request) {
356356
String uri = request.getRequestURI();
357357
for (String path : OPENAPI_PATHS) {
358-
if (uri.equals(path) || uri.startsWith(path + "/")) {
358+
if (uri.endsWith(path) || uri.contains(path + "/")) {
359359
return true;
360360
}
361361
}

modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
5555

5656
logger.trace(logPrefix + "starting ... ");
5757

58+
String uri = request.getRequestURI();
59+
boolean isOpenApiPath = uri.endsWith("/openapi.json") || uri.endsWith("/openapi.yaml") || uri.endsWith("/swagger-ui");
60+
if (isOpenApiPath) {
61+
filterChain.doFilter(request, response);
62+
return;
63+
}
64+
5865
if (!request.getMethod().equals("POST")) {
5966

6067
String ip = "unknown";

modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ public void setAuthenticationManager(AuthenticationManager authenticationManager
5555

5656
@Override
5757
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
58+
String uri = request.getRequestURI();
59+
if (uri.endsWith("/openapi.json") || uri.endsWith("/openapi.yaml") || uri.endsWith("/swagger-ui")) {
60+
return false; // OpenAPI documentation endpoints are public
61+
}
5862
return true;
5963
}
6064

modules/samples/userguide/src/userguide/springbootdemo/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,10 @@
370370
<include name="axis2.xml"/>
371371
</fileset>
372372
</copy>
373+
<!-- Create openapi module archive for WEB-INF/modules -->
374+
<mkdir dir="${project.build.directory}/deploy/axis2-json-api.war/WEB-INF/modules"/>
375+
<copy file="${settings.localRepository}/org/apache/axis2/axis2-openapi/2.0.1-SNAPSHOT/axis2-openapi-2.0.1-SNAPSHOT.jar"
376+
tofile="${project.build.directory}/deploy/axis2-json-api.war/WEB-INF/modules/openapi-2.0.1-SNAPSHOT.mar"/>
373377
<unzip src="${project.build.directory}/axis2-json-api-0.0.1-SNAPSHOT.war" dest="${project.build.directory}/exploded"/>
374378
<jar jarfile="${project.build.directory}/exploded/WEB-INF/services/Login.aar">
375379
<metainf file="resources-axis2/login_resources/services.xml"/>
@@ -385,6 +389,10 @@
385389
<include name="axis2.xml"/>
386390
</fileset>
387391
</copy>
392+
<!-- Create openapi module archive for exploded WEB-INF/modules -->
393+
<mkdir dir="${project.build.directory}/exploded/WEB-INF/modules"/>
394+
<copy file="${settings.localRepository}/org/apache/axis2/axis2-openapi/2.0.1-SNAPSHOT/axis2-openapi-2.0.1-SNAPSHOT.jar"
395+
tofile="${project.build.directory}/exploded/WEB-INF/modules/openapi-2.0.1-SNAPSHOT.mar"/>
388396
</target>
389397
</configuration>
390398
<goals>

modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ class OpenApiRequestMatcher implements RequestMatcher {
349349
public boolean matches(HttpServletRequest request) {
350350
String uri = request.getRequestURI();
351351
for (String path : OPENAPI_PATHS) {
352-
if (uri.equals(path) || uri.startsWith(path + "/")) {
352+
if (uri.endsWith(path) || uri.contains(path + "/")) {
353353
return true;
354354
}
355355
}

modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@
1818
* under the License.
1919
*/
2020
package userguide.springboot.configuration;
21-
21+
2222
import org.apache.logging.log4j.LogManager;
2323
import org.apache.logging.log4j.Logger;
2424
import org.apache.axis2.transport.http.AxisServlet;
2525
import org.springframework.boot.web.servlet.ServletContextInitializer;
26-
import org.springframework.context.annotation.Configuration;
27-
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
26+
import org.springframework.context.annotation.Configuration;
27+
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
2828
import org.springframework.core.annotation.Order;
2929

3030
import org.springframework.beans.factory.annotation.Autowired;
@@ -33,40 +33,49 @@
3333
import org.springframework.context.annotation.PropertySource;
3434
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
3535

36-
import jakarta.servlet.ServletContext;
37-
import jakarta.servlet.ServletRegistration;
36+
import jakarta.servlet.ServletContext;
37+
import jakarta.servlet.ServletRegistration;
38+
39+
import java.util.Set;
3840

39-
import java.util.Set;
40-
4141
@Configuration
4242
@Order(4)
43-
public class Axis2WebAppInitializer implements ServletContextInitializer {
44-
45-
private static final Logger logger = LogManager.getLogger(Axis2WebAppInitializer.class);
46-
private static final String SERVICES_MAPPING = "/services/*";
47-
48-
@Override
49-
public void onStartup(ServletContext container) {
43+
public class Axis2WebAppInitializer implements ServletContextInitializer {
44+
45+
private static final Logger logger = LogManager.getLogger(Axis2WebAppInitializer.class);
46+
private static final String SERVICES_MAPPING = "/services/*";
47+
48+
@Override
49+
public void onStartup(ServletContext container) {
5050
logger.warn("inside onStartup() ...");
51-
// Create the 'root' Spring application context
52-
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
53-
54-
addAxis2Servlet(container, ctx);
51+
// Create the 'root' Spring application context
52+
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
53+
54+
addAxis2Servlet(container, ctx);
55+
addOpenApiServlet(container);
5556
logger.warn("onStartup() completed ...");
5657
}
57-
58-
private void addAxis2Servlet(ServletContext container, AnnotationConfigWebApplicationContext ctx) {
58+
59+
private void addAxis2Servlet(ServletContext container, AnnotationConfigWebApplicationContext ctx) {
5960

6061
ServletRegistration.Dynamic dispatcher = container.addServlet(
6162
"AxisServlet", new AxisServlet());
6263
dispatcher.setLoadOnStartup(1);
6364
Set<String> mappingConflicts = dispatcher.addMapping(SERVICES_MAPPING);
64-
if (!mappingConflicts.isEmpty()) {
65-
for (String s : mappingConflicts) {
66-
logger.error("Mapping conflict: " + s);
67-
}
68-
throw new IllegalStateException("'AxisServlet' could not be mapped to '" + SERVICES_MAPPING + "'");
65+
if (!mappingConflicts.isEmpty()) {
66+
for (String s : mappingConflicts) {
67+
logger.error("Mapping conflict: " + s);
68+
}
69+
throw new IllegalStateException("'AxisServlet' could not be mapped to '" + SERVICES_MAPPING + "'");
6970
}
7071
}
7172

73+
private void addOpenApiServlet(ServletContext container) {
74+
ServletRegistration.Dynamic openApi = container.addServlet(
75+
"OpenApiServlet", new OpenApiServlet());
76+
openApi.setLoadOnStartup(2);
77+
openApi.addMapping("/openapi.json", "/openapi.yaml", "/swagger-ui");
78+
logger.warn("OpenApiServlet registered at /openapi.json, /openapi.yaml, /swagger-ui");
79+
}
80+
7281
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package userguide.springboot.configuration;
20+
21+
import jakarta.servlet.http.HttpServlet;
22+
import jakarta.servlet.http.HttpServletRequest;
23+
import jakarta.servlet.http.HttpServletResponse;
24+
import org.apache.axis2.context.ConfigurationContext;
25+
import org.apache.axis2.openapi.OpenApiModule;
26+
import org.apache.axis2.openapi.SwaggerUIHandler;
27+
import org.apache.axis2.transport.http.AxisServlet;
28+
import org.apache.commons.logging.Log;
29+
import org.apache.commons.logging.LogFactory;
30+
31+
import java.io.IOException;
32+
33+
/**
34+
* Servlet that serves OpenAPI documentation endpoints by delegating to
35+
* the Axis2 OpenAPI module's SwaggerUIHandler.
36+
*
37+
* Registered directly in Axis2WebAppInitializer at:
38+
* /openapi.json - OpenAPI 3.0.1 specification (JSON)
39+
* /openapi.yaml - OpenAPI 3.0.1 specification (YAML)
40+
* /swagger-ui - Interactive Swagger UI documentation
41+
*/
42+
public class OpenApiServlet extends HttpServlet {
43+
44+
private static final Log log = LogFactory.getLog(OpenApiServlet.class);
45+
46+
@Override
47+
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
48+
String uri = request.getRequestURI();
49+
log.info("OpenApiServlet.doGet() called for URI: " + uri);
50+
51+
ConfigurationContext configContext = (ConfigurationContext)
52+
getServletContext().getAttribute(AxisServlet.CONFIGURATION_CONTEXT);
53+
if (configContext == null) {
54+
log.warn("AxisServlet ConfigurationContext not found in ServletContext");
55+
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "OpenAPI module not available");
56+
return;
57+
}
58+
59+
SwaggerUIHandler handler = OpenApiModule.getSwaggerUIHandler(configContext);
60+
if (handler == null) {
61+
log.warn("OpenAPI SwaggerUIHandler not found — ensure openapi module is in WEB-INF/modules");
62+
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "OpenAPI module not initialized");
63+
return;
64+
}
65+
66+
try {
67+
if (uri.endsWith("/openapi.json")) {
68+
handler.handleOpenApiJsonRequest(request, response);
69+
} else if (uri.endsWith("/openapi.yaml")) {
70+
handler.handleOpenApiYamlRequest(request, response);
71+
} else if (uri.contains("/swagger-ui")) {
72+
handler.handleSwaggerUIRequest(request, response);
73+
} else {
74+
response.sendError(HttpServletResponse.SC_NOT_FOUND);
75+
}
76+
} catch (Exception e) {
77+
log.error("OpenApiServlet error handling " + uri + ": " + e.getMessage(), e);
78+
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
79+
}
80+
}
81+
}

modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
5555

5656
logger.trace(logPrefix + "starting ... ");
5757

58+
String uri = request.getRequestURI();
59+
boolean isOpenApiPath = uri.endsWith("/openapi.json") || uri.endsWith("/openapi.yaml") || uri.endsWith("/swagger-ui");
60+
if (isOpenApiPath) {
61+
filterChain.doFilter(request, response);
62+
return;
63+
}
64+
5865
if (!request.getMethod().equals("POST")) {
5966

6067
String ip = "unknown";

modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ public void setAuthenticationManager(AuthenticationManager authenticationManager
5555

5656
@Override
5757
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
58+
String uri = request.getRequestURI();
59+
if (uri.endsWith("/openapi.json") || uri.endsWith("/openapi.yaml") || uri.endsWith("/swagger-ui")) {
60+
return false; // OpenAPI documentation endpoints are public
61+
}
5862
return true;
5963
}
6064

0 commit comments

Comments
 (0)