mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-09 19:45:13 +02:00
[pitboss/grind] deferred session-0034 (20260517T044708Z-e058)
This commit is contained in:
parent
fbd5700578
commit
f4ef3a8ffc
3 changed files with 642 additions and 2 deletions
|
|
@ -555,8 +555,9 @@ pub fn emit(spec: &HarnessSpec) -> Result<HarnessSource, UnsupportedReason> {
|
|||
let entry_source = read_entry_source(&spec.entry_file);
|
||||
let shape = JavaShape::detect(spec, &entry_source);
|
||||
let entry_class = derive_entry_class(&entry_source);
|
||||
let source = generate_harness_java(spec, shape, &entry_class);
|
||||
let extra_files = match shape {
|
||||
let entry_qualifier = derive_entry_qualifier(&entry_source, &entry_class);
|
||||
let source = generate_harness_java(spec, shape, &entry_qualifier);
|
||||
let mut extra_files = match shape {
|
||||
// Real-world servlet sources import `javax.servlet.*` or
|
||||
// `jakarta.servlet.*`; without those symbols on the classpath
|
||||
// `javac` reports `package javax.servlet does not exist` and the
|
||||
|
|
@ -567,6 +568,15 @@ pub fn emit(spec: &HarnessSpec) -> Result<HarnessSource, UnsupportedReason> {
|
|||
}
|
||||
_ => vec![],
|
||||
};
|
||||
// OWASP Benchmark v1.2 fixtures and other Spring-flavoured Java
|
||||
// entry sources reach for `org.owasp.benchmark.helpers.*`,
|
||||
// `org.owasp.esapi.*`, and a small Spring surface (RowMapper,
|
||||
// SqlRowSet, DataAccessException, HtmlUtils). Stage the matching
|
||||
// stub bundle when the entry source signals one of those imports;
|
||||
// non-OWASP harnesses pay zero workdir cost.
|
||||
if crate::dynamic::lang::java_owasp_stubs::entry_needs_owasp_stubs(&entry_source) {
|
||||
extra_files.extend(crate::dynamic::lang::java_owasp_stubs::owasp_stub_files());
|
||||
}
|
||||
|
||||
Ok(HarnessSource {
|
||||
source,
|
||||
|
|
@ -623,6 +633,46 @@ fn derive_entry_class(source: &str) -> String {
|
|||
parse_public_class_name(source).unwrap_or_else(|| "Entry".to_owned())
|
||||
}
|
||||
|
||||
/// Resolve the entry class as a fully-qualified Java name when the
|
||||
/// entry source declares a `package`. Falls back to the bare simple
|
||||
/// name when the source has no package declaration (the legacy
|
||||
/// default-package fixture path).
|
||||
///
|
||||
/// OWASP Benchmark testcases ship with `package
|
||||
/// org.owasp.benchmark.testcode;` headers; javac compiles their
|
||||
/// sources into `org/owasp/benchmark/testcode/<Class>.class` under
|
||||
/// the workdir, so `NyxHarness` (which itself lives in the default
|
||||
/// package) cannot resolve them via the simple name alone. Using
|
||||
/// the FQN in the harness's `Class.forName` / `.class` references
|
||||
/// keeps both default-package and packaged entries linkable.
|
||||
fn derive_entry_qualifier(source: &str, simple_name: &str) -> String {
|
||||
match parse_package_name(source) {
|
||||
Some(pkg) => format!("{pkg}.{simple_name}"),
|
||||
None => simple_name.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_package_name(source: &str) -> Option<String> {
|
||||
for line in source.lines() {
|
||||
let trimmed = line.trim_start();
|
||||
let rest = match trimmed.strip_prefix("package ") {
|
||||
Some(r) => r,
|
||||
None => continue,
|
||||
};
|
||||
let end = rest.find(';')?;
|
||||
let name = rest[..end].trim();
|
||||
if !name.is_empty()
|
||||
&& name
|
||||
.chars()
|
||||
.all(|c| c.is_alphanumeric() || c == '_' || c == '.')
|
||||
{
|
||||
return Some(name.to_owned());
|
||||
}
|
||||
return None;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn parse_public_class_name(source: &str) -> Option<String> {
|
||||
for line in source.lines() {
|
||||
let l = line.trim_start();
|
||||
|
|
@ -1195,6 +1245,133 @@ mod tests {
|
|||
assert!(harness.extra_files.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emit_servlet_doget_bundles_owasp_stubs_when_source_imports_owasp() {
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let entry_file = stage_entry(
|
||||
tmp.path(),
|
||||
"BenchmarkTest00001.java",
|
||||
"package org.owasp.benchmark.testcode;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpServlet;\nimport org.owasp.benchmark.helpers.Utils;\nimport org.owasp.esapi.ESAPI;\npublic class BenchmarkTest00001 extends HttpServlet {\n public void doGet(HttpServletRequest r, HttpServletResponse w) {}\n}\n",
|
||||
);
|
||||
let spec = make_spec_with(EntryKind::HttpRoute, "doGet", &entry_file);
|
||||
let harness = emit(&spec).unwrap();
|
||||
let paths: Vec<&str> = harness.extra_files.iter().map(|(p, _)| p.as_str()).collect();
|
||||
// Servlet stubs are present (same as the non-OWASP servlet case).
|
||||
assert!(paths.contains(&"javax/servlet/http/HttpServletRequest.java"));
|
||||
// OWASP helpers + esapi + spring stubs are appended.
|
||||
assert!(paths.contains(&"org/owasp/benchmark/helpers/Utils.java"));
|
||||
assert!(paths.contains(&"org/owasp/esapi/ESAPI.java"));
|
||||
assert!(paths.contains(&"org/owasp/benchmark/helpers/DatabaseHelper.java"));
|
||||
assert!(paths.contains(&"org/springframework/jdbc/core/RowMapper.java"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emit_servlet_doget_skips_owasp_stubs_when_source_is_plain() {
|
||||
// Servlet entry without OWASP / Spring imports must only carry
|
||||
// the servlet stub bundle, not the OWASP add-on. Keeps workdir
|
||||
// small for the existing servlet_doget fixture path.
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let entry_file = stage_entry(
|
||||
tmp.path(),
|
||||
"Vuln.java",
|
||||
"import javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\npublic class Vuln {\n public void doGet(HttpServletRequest r, HttpServletResponse w) {}\n}\n",
|
||||
);
|
||||
let spec = make_spec_with(EntryKind::HttpRoute, "doGet", &entry_file);
|
||||
let harness = emit(&spec).unwrap();
|
||||
let paths: Vec<&str> = harness.extra_files.iter().map(|(p, _)| p.as_str()).collect();
|
||||
assert!(
|
||||
!paths.iter().any(|p| p.starts_with("org/owasp/")),
|
||||
"plain servlet entry unexpectedly bundles OWASP stubs: {paths:?}"
|
||||
);
|
||||
assert!(
|
||||
!paths.iter().any(|p| p.starts_with("org/springframework/")),
|
||||
"plain servlet entry unexpectedly bundles Spring stubs: {paths:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emit_static_method_with_owasp_imports_bundles_helpers() {
|
||||
// Non-servlet shapes still need the OWASP stub set when the
|
||||
// entry source pulls in helpers (e.g. a plain @Test fixture
|
||||
// calling `Utils.encodeForHTML`).
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let entry_file = stage_entry(
|
||||
tmp.path(),
|
||||
"Vuln.java",
|
||||
"import org.owasp.benchmark.helpers.Utils;\npublic class Vuln {\n public static void run(String p) { Utils.encodeForHTML(p); }\n}\n",
|
||||
);
|
||||
let spec = make_spec_with(EntryKind::Function, "run", &entry_file);
|
||||
let harness = emit(&spec).unwrap();
|
||||
let paths: Vec<&str> = harness.extra_files.iter().map(|(p, _)| p.as_str()).collect();
|
||||
assert!(paths.contains(&"org/owasp/benchmark/helpers/Utils.java"));
|
||||
// No servlet stubs for a non-servlet shape.
|
||||
assert!(!paths.iter().any(|p| p.starts_with("javax/servlet/")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_package_name_handles_packaged_source() {
|
||||
assert_eq!(
|
||||
parse_package_name("package org.owasp.benchmark.testcode;\nclass X {}\n"),
|
||||
Some("org.owasp.benchmark.testcode".to_owned())
|
||||
);
|
||||
// Leading whitespace + extra spaces inside the line are tolerated.
|
||||
assert_eq!(
|
||||
parse_package_name(" package a.b.c ;\n"),
|
||||
Some("a.b.c".to_owned())
|
||||
);
|
||||
// Leading comments / blank lines must not cause an early miss.
|
||||
assert_eq!(
|
||||
parse_package_name("// header comment\n/* block */\npackage com.example;\n"),
|
||||
Some("com.example".to_owned())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_package_name_returns_none_when_absent() {
|
||||
assert_eq!(parse_package_name(""), None);
|
||||
assert_eq!(parse_package_name("public class X {}\n"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_entry_qualifier_uses_package_when_present() {
|
||||
let src = "package org.owasp.benchmark.testcode;\npublic class BenchmarkTest00001 {}\n";
|
||||
assert_eq!(
|
||||
derive_entry_qualifier(src, "BenchmarkTest00001"),
|
||||
"org.owasp.benchmark.testcode.BenchmarkTest00001"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_entry_qualifier_falls_back_to_simple_name() {
|
||||
assert_eq!(derive_entry_qualifier("", "Vuln"), "Vuln");
|
||||
assert_eq!(
|
||||
derive_entry_qualifier("public class Vuln {}", "Vuln"),
|
||||
"Vuln"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emit_static_method_with_packaged_source_uses_fqn_in_harness() {
|
||||
// Packaged entry sources must be addressed by FQN in the
|
||||
// generated NyxHarness, otherwise javac fails with
|
||||
// `cannot find symbol: class <simple_name>` because the
|
||||
// packaged .class lives under `org/owasp/.../<simple>.class`
|
||||
// and NyxHarness itself sits in the default package.
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let entry_file = stage_entry(
|
||||
tmp.path(),
|
||||
"Vuln.java",
|
||||
"package org.example;\npublic class Vuln { public static void run(String p) {} }\n",
|
||||
);
|
||||
let spec = make_spec_with(EntryKind::Function, "run", &entry_file);
|
||||
let harness = emit(&spec).unwrap();
|
||||
assert!(
|
||||
harness.source.contains("org.example.Vuln.run(payload)"),
|
||||
"harness must address packaged entry via FQN; got source:\n{}",
|
||||
harness.source
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emit_spring_controller_carries_no_servlet_stubs() {
|
||||
// Spring controllers do not import `javax.servlet.*`; shipping
|
||||
|
|
|
|||
462
src/dynamic/lang/java_owasp_stubs.rs
Normal file
462
src/dynamic/lang/java_owasp_stubs.rs
Normal file
|
|
@ -0,0 +1,462 @@
|
|||
//! Minimal `org.owasp.benchmark.helpers`, `org.owasp.esapi`, and Spring
|
||||
//! shim stubs for Java harnesses against OWASP Benchmark v1.2 fixtures.
|
||||
//!
|
||||
//! OWASP Benchmark testcases lean on a handful of helper classes that
|
||||
//! ship with the upstream Maven project but are not on the harness
|
||||
//! workdir classpath. Without them `javac` reports
|
||||
//! `error: package org.owasp.benchmark.helpers does not exist` (and
|
||||
//! the matching `esapi` / `springframework` variants) and the verifier
|
||||
//! flips to `BuildFailed` before any sink probe runs.
|
||||
//!
|
||||
//! The bundle here covers the surface OWASP Benchmark v1.2 fixtures
|
||||
//! actually reference (verified by walking
|
||||
//! `~/.cache/nyx/eval_corpus/owasp_benchmark_v1.2/`):
|
||||
//!
|
||||
//! * `org.owasp.benchmark.helpers.Utils` — `testfileDir` field plus
|
||||
//! the encode / OS-command helpers.
|
||||
//! * `org.owasp.benchmark.helpers.DatabaseHelper` — `JDBCtemplate`
|
||||
//! field of stub `BenchmarkJdbcTemplate` type, plus the
|
||||
//! `getSqlConnection` / `getSqlStatement` / `printResults` family.
|
||||
//! * `org.owasp.benchmark.helpers.LDAPManager` — directory-context
|
||||
//! handle pair.
|
||||
//! * `org.owasp.benchmark.helpers.SeparateClassRequest` — wraps a
|
||||
//! `javax.servlet.http.HttpServletRequest` and exposes
|
||||
//! `getTheParameter` / `getTheValue`.
|
||||
//! * `org.owasp.benchmark.helpers.ThingFactory` / `ThingInterface` —
|
||||
//! reflection-style indirection used by reflection-shape fixtures.
|
||||
//! * `org.owasp.esapi.ESAPI` / `org.owasp.esapi.Encoder` — the
|
||||
//! `ESAPI.encoder().encodeForHTML(...)` / `encodeForBase64(...)`
|
||||
//! pair.
|
||||
//! * `org.springframework.dao.DataAccessException` —
|
||||
//! `RowMapper.mapRow` throws it.
|
||||
//! * `org.springframework.jdbc.core.RowMapper` — anonymous-impl
|
||||
//! target.
|
||||
//! * `org.springframework.jdbc.support.rowset.SqlRowSet` — return
|
||||
//! type of `JDBCtemplate.queryForRowSet`.
|
||||
//! * `org.springframework.web.util.HtmlUtils` — `htmlEscape` static.
|
||||
//!
|
||||
//! Methods return null / empty defaults; runtime correctness past the
|
||||
//! `javac` link step is the job of the spec-derivation fallback
|
||||
//! paths, not the build-time stubs.
|
||||
//!
|
||||
//! Detection gate ([`entry_needs_owasp_stubs`]) checks the entry
|
||||
//! source for substring hits on `org.owasp.benchmark` /
|
||||
//! `org.owasp.esapi` / `org.springframework`. Non-OWASP harnesses
|
||||
//! pay zero workdir cost.
|
||||
|
||||
/// Returns `(workdir_relative_path, file_content)` pairs ready to
|
||||
/// drop into [`crate::dynamic::lang::HarnessSource::extra_files`].
|
||||
/// Always returns the full bundle; callers gate on
|
||||
/// [`entry_needs_owasp_stubs`] when scoping is desired.
|
||||
pub fn owasp_stub_files() -> Vec<(String, String)> {
|
||||
vec![
|
||||
(
|
||||
"org/owasp/benchmark/helpers/Utils.java".to_owned(),
|
||||
utils_stub(),
|
||||
),
|
||||
(
|
||||
"org/owasp/benchmark/helpers/DatabaseHelper.java".to_owned(),
|
||||
database_helper_stub(),
|
||||
),
|
||||
(
|
||||
"org/owasp/benchmark/helpers/BenchmarkJdbcTemplate.java".to_owned(),
|
||||
benchmark_jdbc_template_stub(),
|
||||
),
|
||||
(
|
||||
"org/owasp/benchmark/helpers/LDAPManager.java".to_owned(),
|
||||
ldap_manager_stub(),
|
||||
),
|
||||
(
|
||||
"org/owasp/benchmark/helpers/SeparateClassRequest.java".to_owned(),
|
||||
separate_class_request_stub(),
|
||||
),
|
||||
(
|
||||
"org/owasp/benchmark/helpers/ThingFactory.java".to_owned(),
|
||||
thing_factory_stub(),
|
||||
),
|
||||
(
|
||||
"org/owasp/benchmark/helpers/ThingInterface.java".to_owned(),
|
||||
thing_interface_stub(),
|
||||
),
|
||||
(
|
||||
"org/owasp/esapi/ESAPI.java".to_owned(),
|
||||
esapi_stub(),
|
||||
),
|
||||
(
|
||||
"org/owasp/esapi/Encoder.java".to_owned(),
|
||||
encoder_stub(),
|
||||
),
|
||||
(
|
||||
"org/springframework/dao/DataAccessException.java".to_owned(),
|
||||
data_access_exception_stub(),
|
||||
),
|
||||
(
|
||||
"org/springframework/jdbc/core/RowMapper.java".to_owned(),
|
||||
row_mapper_stub(),
|
||||
),
|
||||
(
|
||||
"org/springframework/jdbc/support/rowset/SqlRowSet.java".to_owned(),
|
||||
sql_row_set_stub(),
|
||||
),
|
||||
(
|
||||
"org/springframework/web/util/HtmlUtils.java".to_owned(),
|
||||
html_utils_stub(),
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
/// Substring probe to decide whether an entry source pulls in the
|
||||
/// OWASP Benchmark helper set. Matches `org.owasp.benchmark` /
|
||||
/// `org.owasp.esapi` / `org.springframework` references, including
|
||||
/// import statements and inline FQNs. Conservative on false
|
||||
/// positives: a fixture that only mentions one of these in a comment
|
||||
/// will still get the stubs staged, which is harmless javac work.
|
||||
pub fn entry_needs_owasp_stubs(source: &str) -> bool {
|
||||
source.contains("org.owasp.benchmark")
|
||||
|| source.contains("org.owasp.esapi")
|
||||
|| source.contains("org.springframework")
|
||||
}
|
||||
|
||||
fn utils_stub() -> String {
|
||||
r#"package org.owasp.benchmark.helpers;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
public class Utils {
|
||||
public static String testfileDir = "/tmp/testfiles/";
|
||||
public static String encodeForHTML(String s) { return s == null ? "" : s; }
|
||||
public static String escapeHtml(String s) { return s == null ? "" : s; }
|
||||
public static String htmlEscape(String s) { return s == null ? "" : s; }
|
||||
public static String getFileFromClasspath(String name, ClassLoader cl) { return name; }
|
||||
public static String getInsecureOSCommandString(ClassLoader cl) { return "/bin/sh"; }
|
||||
public static String getOSCommandString(String cmd) { return cmd == null ? "/bin/sh" : cmd; }
|
||||
public static void printOSCommandResults(Process p, Object response) {
|
||||
try {
|
||||
InputStream is = p.getInputStream();
|
||||
if (is != null) { is.close(); }
|
||||
} catch (IOException ignore) {}
|
||||
}
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn database_helper_stub() -> String {
|
||||
r#"package org.owasp.benchmark.helpers;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
public class DatabaseHelper {
|
||||
public static boolean hideSQLErrors = false;
|
||||
public static BenchmarkJdbcTemplate JDBCtemplate = new BenchmarkJdbcTemplate();
|
||||
public static Connection getSqlConnection() throws SQLException { return null; }
|
||||
public static Statement getSqlStatement() throws SQLException { return null; }
|
||||
public static void printResults(ResultSet rs, String sql, Object response) throws SQLException {}
|
||||
public static void printResults(Statement statement, String sql, Object response) throws SQLException {}
|
||||
public static void outputUpdateComplete(String sql, Object response) {}
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn benchmark_jdbc_template_stub() -> String {
|
||||
// Names the small JdbcTemplate-shaped surface OWASP fixtures call
|
||||
// off `DatabaseHelper.JDBCtemplate`. Real Spring JdbcTemplate
|
||||
// ships in spring-jdbc; this stub keeps the link step succeeding
|
||||
// without dragging that jar in.
|
||||
r#"package org.owasp.benchmark.helpers;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
||||
public class BenchmarkJdbcTemplate {
|
||||
public int queryForInt(String sql) { return 0; }
|
||||
public Long queryForLong(String sql) { return 0L; }
|
||||
public List<?> queryForList(String sql) { return Collections.emptyList(); }
|
||||
public Map<String, Object> queryForMap(String sql) { return Collections.emptyMap(); }
|
||||
public <T> T queryForObject(String sql, Object[] args, Class<T> requiredType) { return null; }
|
||||
public SqlRowSet queryForRowSet(String sql) { return null; }
|
||||
public <T> List<T> query(String sql, RowMapper<T> mapper) { return Collections.emptyList(); }
|
||||
public int[] batchUpdate(String sql) { return new int[0]; }
|
||||
public void execute(String sql) {}
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn ldap_manager_stub() -> String {
|
||||
r#"package org.owasp.benchmark.helpers;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
public class LDAPManager {
|
||||
public LDAPManager() {}
|
||||
public DirContext getDirContext() throws NamingException { return null; }
|
||||
public void closeDirContext() {}
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn separate_class_request_stub() -> String {
|
||||
// Real SeparateClassRequest wraps a servlet request and delegates
|
||||
// getTheParameter / getTheValue through to it; the stub keeps the
|
||||
// public surface but discards the request reference.
|
||||
r#"package org.owasp.benchmark.helpers;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
public class SeparateClassRequest {
|
||||
public SeparateClassRequest(HttpServletRequest request) {}
|
||||
public String getTheParameter(String name) { return null; }
|
||||
public String getTheValue(String name) { return null; }
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn thing_factory_stub() -> String {
|
||||
r#"package org.owasp.benchmark.helpers;
|
||||
public class ThingFactory {
|
||||
public static ThingInterface createThing() {
|
||||
return new ThingInterface() {
|
||||
@Override public String doSomething(String input) { return input; }
|
||||
};
|
||||
}
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn thing_interface_stub() -> String {
|
||||
r#"package org.owasp.benchmark.helpers;
|
||||
public interface ThingInterface {
|
||||
String doSomething(String input);
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn esapi_stub() -> String {
|
||||
r#"package org.owasp.esapi;
|
||||
public class ESAPI {
|
||||
private static final Encoder ENCODER = new Encoder() {
|
||||
@Override public String encodeForHTML(String s) { return s == null ? "" : s; }
|
||||
@Override public String encodeForBase64(byte[] b, boolean wrap) {
|
||||
return b == null ? "" : java.util.Base64.getEncoder().encodeToString(b);
|
||||
}
|
||||
};
|
||||
public static Encoder encoder() { return ENCODER; }
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn encoder_stub() -> String {
|
||||
r#"package org.owasp.esapi;
|
||||
public interface Encoder {
|
||||
String encodeForHTML(String s);
|
||||
String encodeForBase64(byte[] b, boolean wrap);
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn data_access_exception_stub() -> String {
|
||||
r#"package org.springframework.dao;
|
||||
public class DataAccessException extends RuntimeException {
|
||||
public DataAccessException(String msg) { super(msg); }
|
||||
public DataAccessException(String msg, Throwable cause) { super(msg, cause); }
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn row_mapper_stub() -> String {
|
||||
r#"package org.springframework.jdbc.core;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
public interface RowMapper<T> {
|
||||
T mapRow(ResultSet rs, int rowNum) throws SQLException, DataAccessException;
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn sql_row_set_stub() -> String {
|
||||
r#"package org.springframework.jdbc.support.rowset;
|
||||
public interface SqlRowSet {
|
||||
boolean next();
|
||||
String getString(int columnIndex);
|
||||
String getString(String columnLabel);
|
||||
int getInt(int columnIndex);
|
||||
int getInt(String columnLabel);
|
||||
Object getObject(int columnIndex);
|
||||
Object getObject(String columnLabel);
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn html_utils_stub() -> String {
|
||||
r#"package org.springframework.web.util;
|
||||
public class HtmlUtils {
|
||||
public static String htmlEscape(String s) { return s == null ? "" : s; }
|
||||
public static String htmlUnescape(String s) { return s == null ? "" : s; }
|
||||
}
|
||||
"#
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn entry_needs_owasp_stubs_detects_helper_imports() {
|
||||
let src = "package x;\nimport org.owasp.benchmark.helpers.Utils;\npublic class V {}\n";
|
||||
assert!(entry_needs_owasp_stubs(src));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn entry_needs_owasp_stubs_detects_esapi_imports() {
|
||||
let src = "import org.owasp.esapi.ESAPI;\npublic class V {}\n";
|
||||
assert!(entry_needs_owasp_stubs(src));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn entry_needs_owasp_stubs_detects_spring_imports() {
|
||||
let src = "import org.springframework.web.util.HtmlUtils;\n";
|
||||
assert!(entry_needs_owasp_stubs(src));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn entry_needs_owasp_stubs_detects_inline_fqn() {
|
||||
// OWASP fixtures often use inline FQNs without an import line.
|
||||
let src = "public class V { void f() { org.owasp.esapi.ESAPI.encoder(); } }";
|
||||
assert!(entry_needs_owasp_stubs(src));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn entry_needs_owasp_stubs_rejects_non_owasp_source() {
|
||||
let src = "public class V { void f() { System.out.println(\"hi\"); } }";
|
||||
assert!(!entry_needs_owasp_stubs(src));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bundle_includes_owasp_helpers() {
|
||||
let paths: Vec<String> = owasp_stub_files()
|
||||
.into_iter()
|
||||
.map(|(p, _)| p)
|
||||
.collect();
|
||||
for required in &[
|
||||
"org/owasp/benchmark/helpers/Utils.java",
|
||||
"org/owasp/benchmark/helpers/DatabaseHelper.java",
|
||||
"org/owasp/benchmark/helpers/BenchmarkJdbcTemplate.java",
|
||||
"org/owasp/benchmark/helpers/LDAPManager.java",
|
||||
"org/owasp/benchmark/helpers/SeparateClassRequest.java",
|
||||
"org/owasp/benchmark/helpers/ThingFactory.java",
|
||||
"org/owasp/benchmark/helpers/ThingInterface.java",
|
||||
"org/owasp/esapi/ESAPI.java",
|
||||
"org/owasp/esapi/Encoder.java",
|
||||
"org/springframework/dao/DataAccessException.java",
|
||||
"org/springframework/jdbc/core/RowMapper.java",
|
||||
"org/springframework/jdbc/support/rowset/SqlRowSet.java",
|
||||
"org/springframework/web/util/HtmlUtils.java",
|
||||
] {
|
||||
assert!(
|
||||
paths.iter().any(|p| p == required),
|
||||
"owasp stub bundle missing {required}; got {paths:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn utils_stub_carries_owasp_method_surface() {
|
||||
let src = utils_stub();
|
||||
for method in &[
|
||||
"testfileDir",
|
||||
"encodeForHTML",
|
||||
"escapeHtml",
|
||||
"htmlEscape",
|
||||
"getFileFromClasspath",
|
||||
"getInsecureOSCommandString",
|
||||
"getOSCommandString",
|
||||
"printOSCommandResults",
|
||||
] {
|
||||
assert!(
|
||||
src.contains(method),
|
||||
"Utils stub missing OWASP surface member `{method}`",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn database_helper_stub_carries_owasp_method_surface() {
|
||||
let src = database_helper_stub();
|
||||
for method in &[
|
||||
"hideSQLErrors",
|
||||
"JDBCtemplate",
|
||||
"getSqlConnection",
|
||||
"getSqlStatement",
|
||||
"printResults",
|
||||
"outputUpdateComplete",
|
||||
] {
|
||||
assert!(
|
||||
src.contains(method),
|
||||
"DatabaseHelper stub missing OWASP surface member `{method}`",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn benchmark_jdbc_template_carries_call_surface() {
|
||||
let src = benchmark_jdbc_template_stub();
|
||||
for method in &[
|
||||
"queryForInt",
|
||||
"queryForLong",
|
||||
"queryForList",
|
||||
"queryForMap",
|
||||
"queryForObject",
|
||||
"queryForRowSet",
|
||||
"query",
|
||||
"batchUpdate",
|
||||
"execute",
|
||||
] {
|
||||
assert!(
|
||||
src.contains(method),
|
||||
"BenchmarkJdbcTemplate stub missing OWASP surface member `{method}`",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoder_stub_declares_two_encode_methods() {
|
||||
let src = encoder_stub();
|
||||
assert!(src.contains("encodeForHTML"));
|
||||
assert!(src.contains("encodeForBase64"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn esapi_stub_returns_anonymous_encoder() {
|
||||
let src = esapi_stub();
|
||||
assert!(src.contains("public static Encoder encoder()"));
|
||||
assert!(src.contains("new Encoder()"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn separate_class_request_takes_servlet_request() {
|
||||
let src = separate_class_request_stub();
|
||||
assert!(src.contains("javax.servlet.http.HttpServletRequest"));
|
||||
assert!(src.contains("getTheParameter"));
|
||||
assert!(src.contains("getTheValue"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bundle_has_thirteen_files() {
|
||||
// Tripwire: 9 OWASP-namespace + 4 spring-namespace stubs. A
|
||||
// count drift here usually means a stub was added without
|
||||
// updating the assertion or a stub got accidentally dropped.
|
||||
let files = owasp_stub_files();
|
||||
assert_eq!(files.len(), 13, "expected 9 owasp + 4 springframework stubs");
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ pub mod c;
|
|||
pub mod cpp;
|
||||
pub mod go;
|
||||
pub mod java;
|
||||
pub mod java_owasp_stubs;
|
||||
pub mod java_servlet_stubs;
|
||||
pub mod javascript;
|
||||
pub mod js_shared;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue