java-topology/defects/openoffice-0002/test/OpenOfficeWebDAVCredentialLogTest.java

126 lines
5.2 KiB
Java

import java.util.*;
import java.util.regex.*;
/**
* openoffice-0002: CurlSession::curlDebugOutput CWE-312 credential logging
*
* Models the HTTP header sanitization logic from curlDebugOutput (CurlSession.cxx).
* Verifies that credential-bearing headers (Authorization, Proxy-Authorization,
* Cookie, etc.) have their values redacted before logging, while non-sensitive
* headers pass through unmodified.
*
* This is a unit test for the MOAD-0004 fix: lcl_IsCredentialHeader() +
* lcl_RedactHeader() added to CurlSession.cxx.
*/
public class OpenOfficeWebDAVCredentialLogTest {
// ---- Model of the fix ----
static boolean isCredentialHeader(String header) {
int colon = header.indexOf(':');
if (colon <= 0) return false;
String name = header.substring(0, colon).trim().toLowerCase();
return name.equals("authorization")
|| name.equals("proxy-authorization")
|| name.equals("x-auth-token")
|| name.equals("www-authenticate")
|| name.equals("proxy-authenticate")
|| name.equals("cookie")
|| name.equals("set-cookie");
}
static String redactHeader(String header) {
int colon = header.indexOf(':');
if (colon <= 0) return header;
return header.substring(0, colon) + ": <redacted>";
}
/** Defective logger: logs header verbatim */
static String defectiveLogHeader(String header) {
return "[CurlHDR ->] " + header;
}
/** Fixed logger: sanitizes credential headers */
static String fixedLogHeader(String header) {
if (isCredentialHeader(header)) {
return "[CurlHDR ->] " + redactHeader(header);
}
return "[CurlHDR ->] " + header;
}
public static void main(String[] args) {
System.out.println("=== openoffice-0002: WebDAV credential header redaction ===\n");
// Test cases: (header, shouldBeRedacted)
Object[][] cases = {
// Credential headers — must be redacted
{ "Authorization: Basic dXNlcjpteXBhc3N3b3Jk", true },
{ "Authorization: Digest username=\"user\", realm=\"realm\", response=\"abc123\"", true },
{ "Proxy-Authorization: Basic cHJveHk6cGFzcw==", true },
{ "Cookie: session=abc123; token=secretvalue", true },
{ "Set-Cookie: auth_token=xyz789; HttpOnly", true },
{ "X-Auth-Token: sk-live-abc123secret", true },
{ "WWW-Authenticate: Basic realm=\"WebDAV\"", true },
{ "Proxy-Authenticate: Digest realm=\"proxy\"", true },
// Non-credential headers — must pass through unmodified
{ "Content-Type: application/xml", false },
{ "DAV: 1, 2, ordered-collections", false },
{ "Host: dav.example.com", false },
{ "User-Agent: OpenOffice/4.2", false },
{ "Content-Length: 512", false },
{ "Transfer-Encoding: chunked", false },
};
int pass = 0, fail = 0;
for (Object[] tc : cases) {
String header = (String) tc[0];
boolean shouldRedact = (boolean) tc[1];
String defOut = defectiveLogHeader(header);
String fixOut = fixedLogHeader(header);
boolean defContainsCred = !defOut.contains("<redacted>") && shouldRedact;
boolean fixCorrect;
if (shouldRedact) {
// Fixed output must contain <redacted> and NOT the original value after colon
fixCorrect = fixOut.contains("<redacted>") && !fixOut.contains(header.substring(header.indexOf(':') + 1).trim());
} else {
// Fixed output must be identical to defective (non-sensitive header)
fixCorrect = fixOut.equals(defOut);
}
String status = fixCorrect ? "PASS" : "FAIL";
if (fixCorrect) pass++; else fail++;
System.out.printf("[%s] %s%n", status, header.substring(0, Math.min(60, header.length())));
if (!fixCorrect) {
System.out.printf(" defective: %s%n", defOut);
System.out.printf(" fixed: %s%n", fixOut);
}
}
System.out.printf("%n%d/%d tests passed%n", pass, pass + fail);
// Key assertion: Authorization: Basic base64 credential must not appear in fixed log
String basicAuthHeader = "Authorization: Basic dXNlcjpteXBhc3N3b3Jk";
String defLog = defectiveLogHeader(basicAuthHeader);
String fixLog = fixedLogHeader(basicAuthHeader);
assert defLog.contains("dXNlcjpteXBhc3N3b3Jk") :
"Defective log should contain credential (demonstrates the bug)";
assert !fixLog.contains("dXNlcjpteXBhc3N3b3Jk") :
"Fixed log must NOT contain base64 credential";
assert fixLog.contains("<redacted>") :
"Fixed log must contain <redacted> placeholder";
// Cookie session token must be redacted
String cookieHeader = "Cookie: session=abc123; token=secretvalue";
assert !fixedLogHeader(cookieHeader).contains("secretvalue") :
"Fixed log must not expose cookie secret values";
assert fail == 0 : fail + " test(s) failed";
System.out.println("\nALL ASSERTIONS PASS");
}
}