|
1
|
|
|
package easytests.swagger; |
|
2
|
|
|
|
|
3
|
|
|
import com.atlassian.oai.validator.model.Request; |
|
4
|
|
|
import com.atlassian.oai.validator.model.Response; |
|
5
|
|
|
import com.atlassian.oai.validator.report.ValidationReport; |
|
6
|
|
|
import java.io.IOException; |
|
7
|
|
|
import javax.servlet.http.HttpServletRequest; |
|
8
|
|
|
import javax.servlet.http.HttpServletResponse; |
|
9
|
|
|
import org.slf4j.Logger; |
|
10
|
|
|
import org.slf4j.LoggerFactory; |
|
11
|
|
|
import org.springframework.core.io.support.EncodedResource; |
|
12
|
|
|
import org.springframework.lang.Nullable; |
|
13
|
|
|
import org.springframework.web.servlet.ModelAndView; |
|
14
|
|
|
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; |
|
15
|
|
|
import org.springframework.web.util.ContentCachingResponseWrapper; |
|
16
|
|
|
|
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* @author atlassian |
|
20
|
|
|
* An Interceptor which validates incoming requests against the defined swagger interface. |
|
21
|
|
|
*/ |
|
22
|
|
|
@SuppressWarnings("checkstyle:MultipleStringLiterals") |
|
23
|
|
|
public class SwaggerValidationInterceptor extends HandlerInterceptorAdapter { |
|
24
|
|
|
|
|
25
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(SwaggerValidationInterceptor.class); |
|
26
|
|
|
|
|
27
|
|
|
private final SwaggerRequestValidationService swaggerRequestValidationService; |
|
28
|
|
|
|
|
29
|
|
|
public SwaggerValidationInterceptor(final EncodedResource swaggerInterface) throws IOException { |
|
30
|
|
|
this(new SwaggerRequestValidationService(swaggerInterface)); |
|
31
|
|
|
} |
|
32
|
|
|
|
|
33
|
|
|
SwaggerValidationInterceptor(final SwaggerRequestValidationService swaggerRequestValidationService) { |
|
34
|
|
|
this.swaggerRequestValidationService = swaggerRequestValidationService; |
|
35
|
|
|
} |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* Validates the given requests. If a request is defined but invalid against the Swagger schema |
|
39
|
|
|
* an {@link InvalidRequestException} will be thrown leading to an error response. |
|
40
|
|
|
* <p> |
|
41
|
|
|
* Only {@link ResettableRequestServletWrapper} can be validated. Wrapping is done within the |
|
42
|
|
|
* {@link SwaggerValidationFilter}. |
|
43
|
|
|
* |
|
44
|
|
|
* @param servletRequest the {@link HttpServletRequest} to validate |
|
45
|
|
|
* @param servletResponse the servlet response |
|
46
|
|
|
* @param handler a handler |
|
47
|
|
|
* @return {@code true} if the request is valid against or not defined in the Swagger schema or |
|
48
|
|
|
* the servlet is not a {@link ResettableRequestServletWrapper} |
|
49
|
|
|
* @throws Exception if the request is invalid against the Swagger schema or the requests body |
|
50
|
|
|
* can't be read |
|
51
|
|
|
*/ |
|
52
|
|
|
@Override |
|
53
|
|
|
public boolean preHandle( |
|
54
|
|
|
final HttpServletRequest servletRequest, |
|
55
|
|
|
final HttpServletResponse servletResponse, |
|
56
|
|
|
final Object handler) throws Exception { |
|
57
|
|
|
// only wrapped servlet requests can be validated - see: SwaggerValidationFilter |
|
58
|
|
|
if (!(servletRequest instanceof ResettableRequestServletWrapper)) { |
|
59
|
|
|
return true; |
|
60
|
|
|
} |
|
61
|
|
|
|
|
62
|
|
|
// validate the request |
|
63
|
|
|
final ResettableRequestServletWrapper resettableRequest = (ResettableRequestServletWrapper) servletRequest; |
|
64
|
|
|
final String requestLoggingKey = servletRequest.getMethod() + "#" + servletRequest.getRequestURI(); |
|
65
|
|
|
LOG.debug("Swagger request validation: {}", requestLoggingKey); |
|
66
|
|
|
|
|
67
|
|
|
final Request request = swaggerRequestValidationService.buildRequest(resettableRequest); |
|
68
|
|
|
final ValidationReport validationReport = swaggerRequestValidationService.validateRequest(request); |
|
69
|
|
|
if (!validationReport.hasErrors()) { |
|
70
|
|
|
LOG.debug("Swagger validation: {} - The request is valid.", requestLoggingKey); |
|
71
|
|
|
} else if (!swaggerRequestValidationService.isDefinedSwaggerRequest(validationReport)) { |
|
72
|
|
|
LOG.info("Swagger validation: {} - The request is not defined in the Swagger schema. Ignoring it.", |
|
73
|
|
|
requestLoggingKey); |
|
74
|
|
|
} else { |
|
75
|
|
|
final InvalidRequestException invalidRequestException = new InvalidRequestException(validationReport); |
|
76
|
|
|
LOG.info("Swagger validation: {} - The REST request is invalid: {}", requestLoggingKey, |
|
77
|
|
|
invalidRequestException.getMessage()); |
|
78
|
|
|
throw invalidRequestException; |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
// reset the requests servlet input stream after reading it on former step |
|
82
|
|
|
resettableRequest.resetInputStream(); |
|
83
|
|
|
return true; |
|
84
|
|
|
} |
|
85
|
|
|
|
|
86
|
|
|
@Override |
|
87
|
|
|
public void postHandle( |
|
88
|
|
|
HttpServletRequest servletRequest, |
|
89
|
|
|
HttpServletResponse servletResponse, |
|
90
|
|
|
Object handler, |
|
91
|
|
|
@Nullable ModelAndView modelAndView) throws Exception { |
|
92
|
|
|
// only wrapped servlet requests can be validated - see: SwaggerValidationFilter |
|
93
|
|
|
if (!(servletRequest instanceof ResettableRequestServletWrapper) |
|
94
|
|
|
|| !(servletResponse instanceof ContentCachingResponseWrapper)) { |
|
95
|
|
|
return; |
|
96
|
|
|
} |
|
97
|
|
|
|
|
98
|
|
|
// validate the request |
|
99
|
|
|
final ResettableRequestServletWrapper resettableRequest = (ResettableRequestServletWrapper) servletRequest; |
|
100
|
|
|
final ContentCachingResponseWrapper cachingResponse = (ContentCachingResponseWrapper) servletResponse; |
|
101
|
|
|
|
|
102
|
|
|
final Request request = swaggerRequestValidationService.buildRequest(resettableRequest); |
|
103
|
|
|
final Response response = swaggerRequestValidationService.buildResponse(cachingResponse); |
|
104
|
|
|
|
|
105
|
|
|
final String requestLoggingKey = servletRequest.getMethod() + "#" + servletRequest.getRequestURI() |
|
106
|
|
|
+ "#" + response.getStatus(); |
|
107
|
|
|
LOG.info("Swagger response validation: {}", requestLoggingKey); |
|
108
|
|
|
|
|
109
|
|
|
final ValidationReport validationReport = swaggerRequestValidationService.validateResponse( |
|
110
|
|
|
request.getPath(), |
|
111
|
|
|
request.getMethod(), |
|
112
|
|
|
response |
|
113
|
|
|
); |
|
114
|
|
|
if (!validationReport.hasErrors()) { |
|
115
|
|
|
LOG.debug("Swagger validation: {} - The response is valid.", requestLoggingKey); |
|
116
|
|
|
} else if (!swaggerRequestValidationService.isDefinedSwaggerRequest(validationReport)) { |
|
117
|
|
|
LOG.info("Swagger validation: {} - The request/response is not defined in the Swagger schema. Ignoring it.", |
|
118
|
|
|
requestLoggingKey); |
|
119
|
|
|
} else { |
|
120
|
|
|
final InvalidResponseException invalidReponseException = new InvalidResponseException(validationReport); |
|
121
|
|
|
LOG.warn("Swagger validation: {} - The REST response is invalid: {}", requestLoggingKey, |
|
122
|
|
|
invalidReponseException.getMessage()); |
|
123
|
|
|
throw invalidReponseException; |
|
124
|
|
|
} |
|
125
|
|
|
} |
|
126
|
|
|
} |
|
127
|
|
|
|