mirror of
https://github.com/servo/servo.git
synced 2025-09-17 02:18:23 +01:00
net: Don't prompt for credentials when 401 response has no WWW-Authenticate
header (#39215)
Testing: Includes a new unit test Fixes: https://github.com/servo/servo/issues/39214 --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
parent
d469e5e564
commit
eec56acd12
2 changed files with 74 additions and 11 deletions
|
@ -27,7 +27,7 @@ use headers::{
|
||||||
};
|
};
|
||||||
use http::header::{
|
use http::header::{
|
||||||
self, ACCEPT, ACCESS_CONTROL_REQUEST_HEADERS, AUTHORIZATION, CONTENT_ENCODING,
|
self, ACCEPT, ACCESS_CONTROL_REQUEST_HEADERS, AUTHORIZATION, CONTENT_ENCODING,
|
||||||
CONTENT_LANGUAGE, CONTENT_LOCATION, CONTENT_TYPE, HeaderValue, RANGE,
|
CONTENT_LANGUAGE, CONTENT_LOCATION, CONTENT_TYPE, HeaderValue, RANGE, WWW_AUTHENTICATE,
|
||||||
};
|
};
|
||||||
use http::{HeaderMap, Method, Request as HyperRequest, StatusCode};
|
use http::{HeaderMap, Method, Request as HyperRequest, StatusCode};
|
||||||
use http_body_util::combinators::BoxBody;
|
use http_body_util::combinators::BoxBody;
|
||||||
|
@ -1719,8 +1719,12 @@ async fn http_network_or_cache_fetch(
|
||||||
// Step 14. If response’s status is 401, httpRequest’s response tainting is not "cors",
|
// Step 14. If response’s status is 401, httpRequest’s response tainting is not "cors",
|
||||||
// includeCredentials is true, and request’s window is an environment settings object, then:
|
// includeCredentials is true, and request’s window is an environment settings object, then:
|
||||||
// TODO(#33616): Figure out what to do with request window objects
|
// TODO(#33616): Figure out what to do with request window objects
|
||||||
if let (Some(StatusCode::UNAUTHORIZED), false, true) =
|
// NOTE: Requiring a WWW-Authenticate header here is ad-hoc, but seems to match what other browsers are
|
||||||
(response.status.try_code(), cors_flag, include_credentials)
|
// doing. See Step 14.1.
|
||||||
|
if response.status.try_code() == Some(StatusCode::UNAUTHORIZED) &&
|
||||||
|
!cors_flag &&
|
||||||
|
include_credentials &&
|
||||||
|
response.headers.contains_key(WWW_AUTHENTICATE)
|
||||||
{
|
{
|
||||||
// TODO: Step 14.1 Spec says requires testing on multiple WWW-Authenticate headers
|
// TODO: Step 14.1 Spec says requires testing on multiple WWW-Authenticate headers
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ use headers::authorization::Basic;
|
||||||
use headers::{
|
use headers::{
|
||||||
Authorization, ContentLength, Date, HeaderMapExt, Host, StrictTransportSecurity, UserAgent,
|
Authorization, ContentLength, Date, HeaderMapExt, Host, StrictTransportSecurity, UserAgent,
|
||||||
};
|
};
|
||||||
use http::header::{self, HeaderMap, HeaderValue};
|
use http::header::{self, HeaderMap, HeaderValue, WWW_AUTHENTICATE};
|
||||||
use http::uri::Authority;
|
use http::uri::Authority;
|
||||||
use http::{HeaderName, Method, StatusCode};
|
use http::{HeaderName, Method, StatusCode};
|
||||||
use http_body_util::combinators::BoxBody;
|
use http_body_util::combinators::BoxBody;
|
||||||
|
@ -1717,6 +1717,10 @@ fn test_prompt_credentials_when_client_receives_unauthorized_response() {
|
||||||
} else {
|
} else {
|
||||||
*response.status_mut() = StatusCode::UNAUTHORIZED;
|
*response.status_mut() = StatusCode::UNAUTHORIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response
|
||||||
|
.headers_mut()
|
||||||
|
.insert(WWW_AUTHENTICATE, HeaderValue::from_static("Basic"));
|
||||||
};
|
};
|
||||||
let (server, url) = make_server(handler);
|
let (server, url) = make_server(handler);
|
||||||
|
|
||||||
|
@ -1744,16 +1748,71 @@ fn test_prompt_credentials_when_client_receives_unauthorized_response() {
|
||||||
|
|
||||||
server.close();
|
server.close();
|
||||||
|
|
||||||
assert!(
|
assert_eq!(
|
||||||
response
|
response.internal_response.unwrap().status.code(),
|
||||||
.internal_response
|
StatusCode::OK
|
||||||
.unwrap()
|
|
||||||
.status
|
|
||||||
.code()
|
|
||||||
.is_success()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dont_prompt_credentials_when_unauthorized_response_contains_no_www_authenticate_header() {
|
||||||
|
let handler =
|
||||||
|
move |request: HyperRequest<Incoming>,
|
||||||
|
response: &mut HyperResponse<BoxBody<Bytes, hyper::Error>>| {
|
||||||
|
assert!(
|
||||||
|
request
|
||||||
|
.headers()
|
||||||
|
.typed_get::<Authorization<Basic>>()
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
|
*response.status_mut() = StatusCode::UNAUTHORIZED;
|
||||||
|
};
|
||||||
|
|
||||||
|
let (server, url) = make_server(handler);
|
||||||
|
|
||||||
|
let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
|
||||||
|
.method(Method::GET)
|
||||||
|
.body(None)
|
||||||
|
.destination(Destination::Document)
|
||||||
|
.mode(RequestMode::Navigate)
|
||||||
|
.origin(mock_origin())
|
||||||
|
.pipeline_id(Some(TEST_PIPELINE_ID))
|
||||||
|
.credentials_mode(CredentialsMode::Include)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let (embedder_proxy, embedder_receiver) = create_embedder_proxy_and_receiver();
|
||||||
|
let handle = std::thread::spawn(move || {
|
||||||
|
loop {
|
||||||
|
let Ok(msg) = embedder_receiver.recv() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
match msg {
|
||||||
|
embedder_traits::EmbedderMsg::RequestAuthentication(..) => {
|
||||||
|
panic!(
|
||||||
|
"Should not have requested authentication as there's no www-authenticate header"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
embedder_traits::EmbedderMsg::WebResourceRequested(..) => {},
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
|
||||||
|
|
||||||
|
let response = fetch_with_context(request, &mut context);
|
||||||
|
|
||||||
|
server.close();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
response.internal_response.unwrap().status.code(),
|
||||||
|
StatusCode::UNAUTHORIZED
|
||||||
|
);
|
||||||
|
|
||||||
|
// Without this join we won't notice if the mock embedder thread panics!
|
||||||
|
drop(context); // Dropping this context causes the embedder thread to exit.
|
||||||
|
handle.join().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prompt_credentials_user_cancels_dialog_input() {
|
fn test_prompt_credentials_user_cancels_dialog_input() {
|
||||||
let handler =
|
let handler =
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue