mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Update tests and add inline expectations
This commit is contained in:
@@ -23,7 +23,6 @@ import java
|
||||
import semmle.code.java.dataflow.FlowSteps
|
||||
import semmle.code.java.frameworks.Servlets
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import MissingHttpOnlyFlow::PathGraph
|
||||
|
||||
/** Gets a regular expression for matching common names of sensitive cookies. */
|
||||
string getSensitiveCookieNameRegex() { result = "(?i).*(auth|session|token|key|credential).*" }
|
||||
@@ -196,6 +195,8 @@ module MissingHttpOnlyConfig implements DataFlow::ConfigSig {
|
||||
|
||||
module MissingHttpOnlyFlow = TaintTracking::Global<MissingHttpOnlyConfig>;
|
||||
|
||||
import MissingHttpOnlyFlow::PathGraph
|
||||
|
||||
from MissingHttpOnlyFlow::PathNode source, MissingHttpOnlyFlow::PathNode sink
|
||||
where MissingHttpOnlyFlow::flowPath(source, sink)
|
||||
select sink, source, sink, "$@ doesn't have the HttpOnly flag set.", source, "This sensitive cookie"
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#select
|
||||
| SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | This sensitive cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | This sensitive cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | This sensitive cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | This sensitive cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | This sensitive cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | This sensitive cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | This sensitive cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | This sensitive cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | This sensitive cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | This sensitive cookie |
|
||||
edges
|
||||
| SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String | provenance | |
|
||||
| SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | provenance | Sink:MaD:46211 |
|
||||
| SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String | SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie | provenance | Config |
|
||||
| SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String | SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie | provenance | MaD:46217 |
|
||||
| SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | provenance | Sink:MaD:46212 |
|
||||
| SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | provenance | Sink:MaD:46212 |
|
||||
| SensitiveCookieNotHttpOnly.java:52:42:52:113 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | provenance | MaD:46260 Sink:MaD:46214 |
|
||||
| SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:52:42:52:113 | new NewCookie(...) : NewCookie | provenance | MaD:46298 |
|
||||
| SensitiveCookieNotHttpOnly.java:63:37:63:115 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:64:25:64:39 | accessKeyCookie : NewCookie | provenance | |
|
||||
| SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:63:37:63:115 | new NewCookie(...) : NewCookie | provenance | MaD:46298 |
|
||||
| SensitiveCookieNotHttpOnly.java:64:25:64:39 | accessKeyCookie : NewCookie | SensitiveCookieNotHttpOnly.java:64:25:64:50 | toString(...) : String | provenance | MaD:46260 |
|
||||
| SensitiveCookieNotHttpOnly.java:64:25:64:50 | toString(...) : String | SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | provenance | Sink:MaD:46214 |
|
||||
| SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | provenance | Sink:MaD:46212 |
|
||||
| SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | provenance | Sink:MaD:46212 |
|
||||
| SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | provenance | Sink:MaD:46212 |
|
||||
| SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | SensitiveCookieNotHttpOnly.java:89:36:89:51 | PRESTO_UI_COOKIE : String | provenance | |
|
||||
| SensitiveCookieNotHttpOnly.java:89:25:89:57 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | provenance | |
|
||||
| SensitiveCookieNotHttpOnly.java:89:36:89:51 | PRESTO_UI_COOKIE : String | SensitiveCookieNotHttpOnly.java:89:25:89:57 | new Cookie(...) : Cookie | provenance | Config |
|
||||
| SensitiveCookieNotHttpOnly.java:89:36:89:51 | PRESTO_UI_COOKIE : String | SensitiveCookieNotHttpOnly.java:89:25:89:57 | new Cookie(...) : Cookie | provenance | MaD:46217 |
|
||||
| SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie | provenance | |
|
||||
| SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | provenance | Sink:MaD:46211 |
|
||||
nodes
|
||||
| SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | semmle.label | "jwt_token" : String |
|
||||
| SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie | semmle.label | new Cookie(...) : Cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String | semmle.label | tokenCookieStr : String |
|
||||
| SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | semmle.label | jwtCookie |
|
||||
| SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | semmle.label | "token=" : String |
|
||||
| SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | semmle.label | ... + ... |
|
||||
| SensitiveCookieNotHttpOnly.java:52:42:52:113 | new NewCookie(...) : NewCookie | semmle.label | new NewCookie(...) : NewCookie |
|
||||
| SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | semmle.label | toString(...) |
|
||||
| SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | semmle.label | "session-access-key" : String |
|
||||
| SensitiveCookieNotHttpOnly.java:63:37:63:115 | new NewCookie(...) : NewCookie | semmle.label | new NewCookie(...) : NewCookie |
|
||||
| SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | semmle.label | "session-access-key" : String |
|
||||
| SensitiveCookieNotHttpOnly.java:64:25:64:39 | accessKeyCookie : NewCookie | semmle.label | accessKeyCookie : NewCookie |
|
||||
| SensitiveCookieNotHttpOnly.java:64:25:64:50 | toString(...) : String | semmle.label | toString(...) : String |
|
||||
| SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | semmle.label | keyStr |
|
||||
| SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | semmle.label | "token=" : String |
|
||||
| SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | semmle.label | secString |
|
||||
| SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | semmle.label | "Presto-UI-Token" : String |
|
||||
| SensitiveCookieNotHttpOnly.java:89:25:89:57 | new Cookie(...) : Cookie | semmle.label | new Cookie(...) : Cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:89:36:89:51 | PRESTO_UI_COOKIE : String | semmle.label | PRESTO_UI_COOKIE : String |
|
||||
| SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | semmle.label | cookie : Cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie | semmle.label | createAuthenticationCookie(...) : Cookie |
|
||||
| SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | semmle.label | cookie |
|
||||
subpaths
|
||||
@@ -0,0 +1,164 @@
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import javax.ws.rs.core.NewCookie;
|
||||
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
|
||||
class SensitiveCookieNotHttpOnly {
|
||||
// GOOD - Tests adding a sensitive cookie with the `HttpOnly` flag set.
|
||||
public void addCookie(String jwt_token, HttpServletRequest request, HttpServletResponse response) {
|
||||
Cookie jwtCookie = new Cookie("jwt_token", jwt_token);
|
||||
jwtCookie.setPath("/");
|
||||
jwtCookie.setMaxAge(3600*24*7);
|
||||
jwtCookie.setHttpOnly(true);
|
||||
response.addCookie(jwtCookie);
|
||||
}
|
||||
|
||||
// BAD - Tests adding a sensitive cookie without the `HttpOnly` flag set.
|
||||
public void addCookie2(String jwt_token, String userId, HttpServletRequest request, HttpServletResponse response) {
|
||||
String tokenCookieStr = "jwt_token"; // $Source
|
||||
Cookie jwtCookie = new Cookie(tokenCookieStr, jwt_token);
|
||||
Cookie userIdCookie = new Cookie("user_id", userId);
|
||||
jwtCookie.setPath("/");
|
||||
userIdCookie.setPath("/");
|
||||
jwtCookie.setMaxAge(3600*24*7);
|
||||
userIdCookie.setMaxAge(3600*24*7);
|
||||
response.addCookie(jwtCookie); // $Alert
|
||||
response.addCookie(userIdCookie);
|
||||
}
|
||||
|
||||
// GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set.
|
||||
public void addCookie3(String authId, HttpServletRequest request, HttpServletResponse response) {
|
||||
response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure");
|
||||
}
|
||||
|
||||
// BAD - Tests set a sensitive cookie header without the `HttpOnly` flag set.
|
||||
public void addCookie4(String authId, HttpServletRequest request, HttpServletResponse response) {
|
||||
response.addHeader("Set-Cookie", "token=" +authId + ";Secure"); // $Alert
|
||||
}
|
||||
|
||||
// GOOD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` with the `HttpOnly` flag set through string concatenation.
|
||||
public void addCookie5(String accessKey, HttpServletRequest request, HttpServletResponse response) {
|
||||
response.setHeader("Set-Cookie", new NewCookie("session-access-key", accessKey, "/", null, null, 0, true) + ";HttpOnly");
|
||||
}
|
||||
|
||||
// BAD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` without the `HttpOnly` flag set.
|
||||
public void addCookie6(String accessKey, HttpServletRequest request, HttpServletResponse response) {
|
||||
response.setHeader("Set-Cookie", new NewCookie("session-access-key", accessKey, "/", null, null, 0, true).toString()); // $Alert
|
||||
}
|
||||
|
||||
// GOOD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` with the `HttpOnly` flag set through the constructor.
|
||||
public void addCookie7(String accessKey, HttpServletRequest request, HttpServletResponse response) {
|
||||
NewCookie accessKeyCookie = new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true);
|
||||
response.setHeader("Set-Cookie", accessKeyCookie.toString());
|
||||
}
|
||||
|
||||
// BAD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` without the `HttpOnly` flag set.
|
||||
public void addCookie8(String accessKey, HttpServletRequest request, HttpServletResponse response) {
|
||||
NewCookie accessKeyCookie = new NewCookie("session-access-key", accessKey, "/", null, 0, null, 86400, true); // $Source
|
||||
String keyStr = accessKeyCookie.toString();
|
||||
response.setHeader("Set-Cookie", keyStr); // $Alert
|
||||
}
|
||||
|
||||
// BAD - Tests set a sensitive cookie header using a variable without the `HttpOnly` flag set.
|
||||
public void addCookie9(String authId, HttpServletRequest request, HttpServletResponse response) {
|
||||
String secString = "token=" +authId + ";Secure"; // $Source
|
||||
response.addHeader("Set-Cookie", secString); // $Alert
|
||||
}
|
||||
|
||||
// GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set using `String.format(...)`.
|
||||
public void addCookie10(HttpServletRequest request, HttpServletResponse response) {
|
||||
response.addHeader("SET-COOKIE", String.format("%s=%s;HttpOnly", "sessionkey", request.getSession().getAttribute("sessionkey")));
|
||||
}
|
||||
|
||||
public Cookie createHttpOnlyAuthenticationCookie(HttpServletRequest request, String jwt) {
|
||||
String PRESTO_UI_COOKIE = "Presto-UI-Token";
|
||||
Cookie cookie = new Cookie(PRESTO_UI_COOKIE, jwt);
|
||||
cookie.setHttpOnly(true);
|
||||
cookie.setPath("/ui");
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public Cookie createAuthenticationCookie(HttpServletRequest request, String jwt) {
|
||||
String PRESTO_UI_COOKIE = "Presto-UI-Token"; // $Source
|
||||
Cookie cookie = new Cookie(PRESTO_UI_COOKIE, jwt);
|
||||
cookie.setPath("/ui");
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public Cookie removeAuthenticationCookie(HttpServletRequest request, String jwt) {
|
||||
String PRESTO_UI_COOKIE = "Presto-UI-Token";
|
||||
Cookie cookie = new Cookie(PRESTO_UI_COOKIE, jwt);
|
||||
cookie.setPath("/ui");
|
||||
cookie.setMaxAge(0);
|
||||
return cookie;
|
||||
}
|
||||
|
||||
// GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set using a wrapper method.
|
||||
public void addCookie11(HttpServletRequest request, HttpServletResponse response, String jwt) {
|
||||
Cookie cookie = createHttpOnlyAuthenticationCookie(request, jwt);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
// BAD - Tests set a sensitive cookie header without the `HttpOnly` flag set using a wrapper method.
|
||||
public void addCookie12(HttpServletRequest request, HttpServletResponse response, String jwt) {
|
||||
Cookie cookie = createAuthenticationCookie(request, jwt);
|
||||
response.addCookie(cookie); // $Alert
|
||||
}
|
||||
|
||||
// GOOD - Tests remove a sensitive cookie header without the `HttpOnly` flag set using a wrapper method.
|
||||
public void addCookie13(HttpServletRequest request, HttpServletResponse response, String jwt) {
|
||||
Cookie cookie = removeAuthenticationCookie(request, jwt);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
private Cookie createCookie(String name, String value, Boolean httpOnly){
|
||||
Cookie cookie = null;
|
||||
cookie = new Cookie(name, value);
|
||||
cookie.setDomain("/");
|
||||
cookie.setHttpOnly(httpOnly);
|
||||
|
||||
//for production https
|
||||
cookie.setSecure(true);
|
||||
|
||||
cookie.setMaxAge(60*60*24*30);
|
||||
cookie.setPath("/");
|
||||
|
||||
return cookie;
|
||||
}
|
||||
|
||||
// GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set through a boolean variable using a wrapper method.
|
||||
public void addCookie14(HttpServletRequest request, HttpServletResponse response, String refreshToken) {
|
||||
response.addCookie(createCookie("refresh_token", refreshToken, true));
|
||||
}
|
||||
|
||||
// BAD (but not detected) - Tests set a sensitive cookie header with the `HttpOnly` flag not set through a boolean variable using a wrapper method.
|
||||
// This example is missed because the `cookie.setHttpOnly` call in `createCookie` is thought to maybe set the HTTP-only flag, and the `cookie`
|
||||
// object flows to this `addCookie` call.
|
||||
public void addCookie15(HttpServletRequest request, HttpServletResponse response, String refreshToken) {
|
||||
response.addCookie(createCookie("refresh_token", refreshToken, false)); // $MISSING:Alert
|
||||
}
|
||||
|
||||
// GOOD - CSRF token doesn't need to have the `HttpOnly` flag set.
|
||||
public void addCsrfCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
// Spring put the CSRF token in session attribute "_csrf"
|
||||
CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
|
||||
|
||||
// Send the cookie only if the token has changed
|
||||
String actualToken = request.getHeader("X-CSRF-TOKEN");
|
||||
if (actualToken == null || !actualToken.equals(csrfToken.getToken())) {
|
||||
// Session cookie that can be used by AngularJS
|
||||
String pCookieName = "CSRF-TOKEN";
|
||||
Cookie cookie = new Cookie(pCookieName, csrfToken.getToken());
|
||||
cookie.setMaxAge(-1);
|
||||
cookie.setHttpOnly(false);
|
||||
cookie.setPath("/");
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
query: Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
1
java/ql/test/query-tests/security/CWE-1004/options
Normal file
1
java/ql/test/query-tests/security/CWE-1004/options
Normal file
@@ -0,0 +1 @@
|
||||
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/springframework-5.8.x
|
||||
Reference in New Issue
Block a user