Skip to content

Java: Fix SpringRequestMappingMethod URL Extraction #2 #19556

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 22, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: deprecated
---
* The predicate `getValue()` on `SpringRequestMappingMethod` is now deprecated. Use `getAValue()` instead.
Original file line number Diff line number Diff line change
@@ -153,8 +153,16 @@ class SpringRequestMappingMethod extends SpringControllerMethod {
result = this.getProducesExpr().(CompileTimeConstantExpr).getStringValue()
}

/** Gets the "value" @RequestMapping annotation value, if present. */
string getValue() { result = requestMappingAnnotation.getStringValue("value") }
/** DEPRECATED: Use `getAValue()` instead. */
deprecated string getValue() { result = requestMappingAnnotation.getStringValue("value") }

/**
* Gets a "value" @RequestMapping annotation string value, if present.
*
* If the annotation element is defined with an array initializer, then the result will be one of the
* elements of that array. Otherwise, the result will be the single expression used as value.
*/
string getAValue() { result = requestMappingAnnotation.getAStringArrayValue("value") }

/** Gets the "method" @RequestMapping annotation value, if present. */
string getMethodValue() {
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import java
import utils.test.InlineExpectationsTest
private import semmle.code.java.frameworks.spring.SpringController

module TestRequestController implements TestSig {
string getARelevantTag() { result = "RequestMappingURL" }

predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "RequestMappingURL" and
exists(SpringRequestMappingMethod m |
m.getLocation() = location and
element = m.toString() and
value = "\"" + m.getAValue() + "\""
)
}
}

import MakeTest<TestRequestController>
72 changes: 40 additions & 32 deletions java/ql/test/library-tests/frameworks/spring/controller/Test.java
Original file line number Diff line number Diff line change
@@ -32,155 +32,156 @@

public class Test {

static void sink(Object o) {}
static void sink(Object o) {
}

@Controller
static class NotTaintedTest {
@RequestMapping("/")
public void get(WebRequest src) {
public void get(WebRequest src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(NativeWebRequest src) {
public void get(NativeWebRequest src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(ServletRequest src) {
public void get(ServletRequest src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(HttpSession src) {
public void get(HttpSession src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(PushBuilder src) {
public void get(PushBuilder src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(Principal src) {
public void get(Principal src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(HttpMethod src) {
public void get(HttpMethod src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(Locale src) {
public void get(Locale src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(TimeZone src) {
public void get(TimeZone src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(ZoneId src) {
public void get(ZoneId src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(OutputStream src) {
public void get(OutputStream src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(Writer src) {
public void get(Writer src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(RedirectAttributes src) {
public void get(RedirectAttributes src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(Errors src) {
public void get(Errors src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(SessionStatus src) {
public void get(SessionStatus src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(UriComponentsBuilder src) {
public void get(UriComponentsBuilder src) { // $ RequestMappingURL="/"
sink(src);
}

@RequestMapping("/")
public void get(Pageable src) {
public void get(Pageable src) { // $ RequestMappingURL="/"
sink(src);
}
}

@Controller
static class ExplicitlyTaintedTest {
@RequestMapping("/")
public void get(InputStream src) {
public void get(InputStream src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void get(Reader src) {
public void get(Reader src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void matrixVariable(@MatrixVariable Object src) {
public void matrixVariable(@MatrixVariable Object src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void requestParam(@RequestParam Object src) {
public void requestParam(@RequestParam Object src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void requestHeader(@RequestHeader Object src) {
public void requestHeader(@RequestHeader Object src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void cookieValue(@CookieValue Object src) {
public void cookieValue(@CookieValue Object src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void requestPart(@RequestPart Object src) {
public void requestPart(@RequestPart Object src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void pathVariable(@PathVariable Object src) {
public void pathVariable(@PathVariable Object src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void requestBody(@RequestBody Object src) {
public void requestBody(@RequestBody Object src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void get(HttpEntity src) {
public void get(HttpEntity src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void requestAttribute(@RequestAttribute Object src) {
public void requestAttribute(@RequestAttribute Object src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void sessionAttribute(@SessionAttribute Object src) {
public void sessionAttribute(@SessionAttribute Object src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}
}
@@ -191,13 +192,20 @@ static class Pojo {
}

@RequestMapping("/")
public void get(String src) {
public void get(String src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}

@RequestMapping("/")
public void get1(Pojo src) {
public void get1(Pojo src) { // $ RequestMappingURL="/"
sink(src); // $hasValueFlow
}
}

@Controller
static class MultipleValuesTest {
@RequestMapping({"/a", "/b"})
public void get(WebRequest src) { // $ RequestMappingURL="/a" RequestMappingURL="/b"
}
}
}