126 lines
5.2 KiB
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");
|
|
}
|
|
}
|