Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Regression test for bug 2034752: ProcessSecurityHeaders failure must not
// prevent HTTP authentication on a 401 response.
"use strict";
const { NodeHTTPSServer } = ChromeUtils.importESModule(
);
do_get_profile();
Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
class AuthPrompt {
constructor() {
this.calls = 0;
}
QueryInterface = ChromeUtils.generateQI(["nsIAuthPrompt2"]);
asyncPromptAuth(channel, callback, context, level, authInfo) {
this.calls++;
authInfo.username = "user";
authInfo.password = "pass";
executeSoon(() => callback.onAuthAvailable(context, authInfo));
}
}
class Requestor {
constructor() {
this.prompt = new AuthPrompt();
}
QueryInterface = ChromeUtils.generateQI(["nsIInterfaceRequestor"]);
getInterface(iid) {
if (iid.equals(Ci.nsIAuthPrompt2)) {
return this.prompt;
}
throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
}
}
add_task(async function test_https_401_with_hsts_and_cert_override() {
Services.prefs.setIntPref("network.auth.subresource-http-auth-allow", 2);
// Use an untrusted cert so ProcessHSTSHeader fails (it rejects HSTS for
// connections with cert errors). setDisableAllSecurityChecks lets the
// connection proceed despite the bad cert.
let server = new NodeHTTPSServer();
server._skipCert = true;
await server.start();
let certOverrideService = Cc[
"@mozilla.org/security/certoverride;1"
].getService(Ci.nsICertOverrideService);
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
true
);
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("network.auth.subresource-http-auth-allow");
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
false
);
await server.stop();
});
await server.registerPathHandler("/auth", (req, resp) => {
if (req.headers.authorization) {
resp.writeHead(200, { "Content-Type": "text/plain" });
resp.end("ok");
return;
}
resp.writeHead(401, {
"WWW-Authenticate": 'Basic realm="testrealm"',
"Strict-Transport-Security": "max-age=600",
"Content-Type": "text/plain",
});
resp.end("auth required");
});
let principal = Services.scriptSecurityManager.createContentPrincipal(
Services.io.newURI(`https://localhost:${server.port()}`),
{}
);
let chan = NetUtil.newChannel({
uri: `https://localhost:${server.port()}/auth`,
loadingPrincipal: principal,
securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER,
}).QueryInterface(Ci.nsIHttpChannel);
let requestor = new Requestor();
chan.notificationCallbacks = requestor;
let [request, buffer] = await new Promise(resolve => {
chan.asyncOpen(
new ChannelListener(
(req, buff) => resolve([req, buff]),
null,
CL_ALLOW_UNKNOWN_CL
)
);
});
Assert.equal(request.status, Cr.NS_OK, "channel succeeded");
Assert.equal(
request.QueryInterface(Ci.nsIHttpChannel).responseStatus,
200,
"server returned 200 after authentication"
);
Assert.equal(buffer, "ok", "got expected response body");
Assert.equal(requestor.prompt.calls, 1, "auth prompt was invoked once");
});