Prompt user for credentials when http request needs it (#34620)

* prompt user to get their credentials

Signed-off-by: Lloyd Massiah artmis9@protonmail.com

move credential prompt to a function

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* add prompt for step 15.4

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* add new prompt definition for user credentials

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* remove default implementation for HttpState which allowed making the embedder_proxy non-optional

- default implementation was only used in tests so created an alternative create_http_state function

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

add credentials to authentication cache

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* add tests that are successful for the happy path

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* add test for user cancels prompt and user inputs incorrect credentials, and refactor shared code between tests

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* handle error when setting username and password in Url and ran formatting

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

renaming test functions

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* change authentication flag to false for proxy authentication. The spec doesn't specify that the flag should be true, and the flag is by default false

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* clean up test code a bit

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* add skeleton implementation to support open harmony and android

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* update warning message to include Android

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* fix build error for OH os and Android

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

* remove unused import to fix warning

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>

---------

Signed-off-by: Lloyd Massiah <artmis9@protonmail.com>
Co-authored-by: lazypassion <25536767+lazypassion@users.noreply.github.com>
This commit is contained in:
arthmis 2024-12-28 15:24:11 -05:00 committed by GitHub
parent a9539d8b03
commit aa40b8f820
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 379 additions and 51 deletions

View file

@ -6,7 +6,6 @@
use std::collections::HashMap;
use std::io::Write;
use std::str;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use std::time::Duration;
@ -47,7 +46,10 @@ use servo_url::{ImmutableOrigin, ServoUrl};
use tokio_test::block_on;
use url::Url;
use crate::{fetch, fetch_with_context, make_server, new_fetch_context};
use crate::{
create_embedder_proxy_and_receiver, fetch, fetch_with_context, make_server, new_fetch_context,
receive_credential_prompt_msgs,
};
fn mock_origin() -> ImmutableOrigin {
ServoUrl::parse("http://servo.org").unwrap().origin()
@ -1479,3 +1481,180 @@ fn test_origin_serialization_compatability() {
ensure_serialiations_match("data:,dataurltexta");
}
#[test]
fn test_user_credentials_prompt_when_proxy_authentication_is_required() {
let handler = move |request: HyperRequest<Body>, response: &mut HyperResponse<Body>| {
let expected = Authorization::basic("username", "test");
if let Some(credentials) = request.headers().typed_get::<Authorization<Basic>>() {
if credentials == expected {
*response.status_mut() = StatusCode::OK;
} else {
*response.status_mut() = StatusCode::UNAUTHORIZED;
}
} else {
*response.status_mut() = StatusCode::PROXY_AUTHENTICATION_REQUIRED;
}
};
let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
.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 _ = receive_credential_prompt_msgs(
embedder_receiver,
Some("username".to_string()),
Some("test".to_string()),
);
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
let response = fetch_with_context(&mut request, &mut context);
let _ = server.close();
assert!(response
.internal_response
.unwrap()
.status
.code()
.is_success());
}
#[test]
fn test_prompt_credentials_when_client_receives_unauthorized_response() {
let handler = move |request: HyperRequest<Body>, response: &mut HyperResponse<Body>| {
let expected = Authorization::basic("username", "test");
if let Some(credentials) = request.headers().typed_get::<Authorization<Basic>>() {
if credentials == expected {
*response.status_mut() = StatusCode::OK;
} else {
*response.status_mut() = StatusCode::UNAUTHORIZED;
}
} else {
*response.status_mut() = StatusCode::UNAUTHORIZED;
}
};
let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
.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 _ = receive_credential_prompt_msgs(
embedder_receiver,
Some("username".to_string()),
Some("test".to_string()),
);
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
let response = fetch_with_context(&mut request, &mut context);
server.close();
assert!(response
.internal_response
.unwrap()
.status
.code()
.is_success());
}
#[test]
fn test_prompt_credentials_user_cancels_dialog_input() {
let handler = move |request: HyperRequest<Body>, response: &mut HyperResponse<Body>| {
let expected = Authorization::basic("username", "test");
if let Some(credentials) = request.headers().typed_get::<Authorization<Basic>>() {
if credentials == expected {
*response.status_mut() = StatusCode::OK;
} else {
*response.status_mut() = StatusCode::UNAUTHORIZED;
}
} else {
*response.status_mut() = StatusCode::UNAUTHORIZED;
}
};
let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
.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 _ = receive_credential_prompt_msgs(embedder_receiver, None, None);
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
let response = fetch_with_context(&mut request, &mut context);
server.close();
assert!(response
.internal_response
.unwrap()
.status
.code()
.is_client_error());
}
#[test]
fn test_prompt_credentials_user_input_incorrect_credentials() {
let handler = move |request: HyperRequest<Body>, response: &mut HyperResponse<Body>| {
let expected = Authorization::basic("username", "test");
if let Some(credentials) = request.headers().typed_get::<Authorization<Basic>>() {
if credentials == expected {
*response.status_mut() = StatusCode::OK;
} else {
*response.status_mut() = StatusCode::UNAUTHORIZED;
}
} else {
*response.status_mut() = StatusCode::UNAUTHORIZED;
}
};
let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
.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 _ = receive_credential_prompt_msgs(
embedder_receiver,
Some("test".to_string()),
Some("test".to_string()),
);
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
let response = fetch_with_context(&mut request, &mut context);
server.close();
assert!(response
.internal_response
.unwrap()
.status
.code()
.is_client_error());
}