Commit 0b83780d authored by johan's avatar johan
Browse files

File transfer supports digest auth

parent c7fc6196
......@@ -230,22 +230,8 @@ static void _chat_message_process_response_from_post_file (void *data, const bel
d->processResponseFromPostFile(event);
}
void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_http_response_event_t *event) {
if (httpRequest && !isFileTransferInProgressAndValid()) {
releaseHttpRequest();
return;
}
shared_ptr<ChatMessage> message = chatMessage.lock();
if (!message)
return;
// check the answer code
if (event->response) {
int code = belle_http_response_get_status_code(event->response);
if (code == 204) { // this is the reply to the first post to the server - an empty msg
belle_sip_body_handler_t *FileTransferChatMessageModifier::prepare_upload_body_handler(shared_ptr<ChatMessage> message) {
// start uploading the file
belle_sip_multipart_body_handler_t *bh;
string first_part_header;
belle_sip_body_handler_t *first_part_bh;
......@@ -317,11 +303,27 @@ void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_h
currentFileContentToTransfer->getContentType().getSubType().c_str()));
// insert it in a multipart body handler which will manage the boundaries of multipart msg
bh = belle_sip_multipart_body_handler_new(_chat_message_file_transfer_on_progress, this, first_part_bh, nullptr);
return (BELLE_SIP_BODY_HANDLER(belle_sip_multipart_body_handler_new(_chat_message_file_transfer_on_progress, this, first_part_bh, nullptr)));
}
void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_http_response_event_t *event) {
if (httpRequest && !isFileTransferInProgressAndValid()) {
releaseHttpRequest();
return;
}
shared_ptr<ChatMessage> message = chatMessage.lock();
if (!message)
return;
// check the answer code
if (event->response) {
int code = belle_http_response_get_status_code(event->response);
if (code == 204) { // this is the reply to the first post to the server - an empty msg
auto bh = prepare_upload_body_handler(message);
releaseHttpRequest();
fileUploadBeginBackgroundTask();
uploadFile(BELLE_SIP_BODY_HANDLER(bh));
uploadFile(bh);
} else if (code == 200) { // file has been uploaded correctly, get server reply and send it
const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response);
if (body && strlen(body) > 0) {
......@@ -430,6 +432,15 @@ void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_h
delete currentFileTransferContent;
currentFileTransferContent = nullptr;
message->getPrivate()->setState(ChatMessage::State::FileTransferError);
releaseHttpRequest();
fileUploadEndBackgroundTask();
} else if (code == 401) {
lWarning() << "Received HTTP code response " << code << " for file transfer, probably meaning that our credentials were rejected";
message->getPrivate()->removeContent(currentFileTransferContent);
delete currentFileTransferContent;
currentFileTransferContent = nullptr;
message->getPrivate()->setState(ChatMessage::State::FileTransferError);
releaseHttpRequest();
fileUploadEndBackgroundTask();
......@@ -475,6 +486,21 @@ void FileTransferChatMessageModifier::processAuthRequestedUpload (belle_sip_auth
* - Stored auth information in linphone core are indexed by username/domain */
linphone_core_fill_belle_sip_auth_event(message->getCore()->getCCore(), event, address.getUsername().data(), address.getDomain().data());
// For digest auth: If there is no body handler, now it is a good time to add it
if (belle_sip_auth_event_get_mode(event) == BELLE_SIP_AUTH_MODE_HTTP_DIGEST) {
if (belle_sip_message_get_body_handler(BELLE_SIP_MESSAGE(httpRequest)) == NULL) {
lInfo()<<"File upload: Add a body handler to the message during auth request";
auto bh = prepare_upload_body_handler(message);
fileUploadBeginBackgroundTask();
if (bh) belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(httpRequest), BELLE_SIP_BODY_HANDLER(bh));
} else { // There is already a body handler, it means our credentials were rejected by the server
lError()<<"File upload failed because our credentials are rejected by the server - give up on this transfer";
// Cancel found credentials so the 401 code will flow to the response handler and the upload will be cancelled
belle_sip_auth_event_set_passwd(event, NULL);
belle_sip_auth_event_set_ha1(event, NULL);
belle_sip_auth_event_set_algorithm(event, NULL);
}
}
}
int FileTransferChatMessageModifier::uploadFile (belle_sip_body_handler_t *bh) {
......@@ -526,7 +552,8 @@ int FileTransferChatMessageModifier::startHttpTransfer (const string &url, const
httpRequest = belle_http_request_create(
action.c_str(),
uri,
belle_sip_header_create("User-Agent", linphone_core_get_user_agent(message->getCore()->getCCore())),
belle_http_header_create("User-Agent", linphone_core_get_user_agent(message->getCore()->getCCore())),
belle_http_header_create("From", message->getLocalAdress().asString().c_str()),
nullptr
);
......
......@@ -75,6 +75,7 @@ private:
void onDownloadFailed ();
void releaseHttpRequest ();
belle_sip_body_handler_t *prepare_upload_body_handler(std::shared_ptr<ChatMessage> message);
std::weak_ptr<ChatMessage> chatMessage;
FileContent* currentFileContentToTransfer = nullptr;
......
......@@ -157,6 +157,8 @@ extern const char* test_route;
extern const char* userhostsfile;
extern const char* file_transfer_url;
extern const char* file_transfer_url_tls_client_auth;
extern const char* file_transfer_url_digest_auth;
extern const char* file_transfer_url_digest_auth_any_domain;
extern const char* lime_server_c25519_url;
extern const char* lime_server_c448_url;
extern const char* lime_server_any_domain_c25519_url;
......
......@@ -597,7 +597,7 @@ static void text_message_in_call_chat_room_from_denied_text_offer(void) {
void transfer_message_base3(LinphoneCoreManager* marie, LinphoneCoreManager* pauline, bool_t upload_error, bool_t download_error,
bool_t use_file_body_handler_in_upload, bool_t use_file_body_handler_in_download, bool_t download_from_history,
int auto_download, bool_t two_files, bool_t legacy, const char* url) {
int auto_download, bool_t two_files, bool_t legacy, const char* url, bool_t expect_auth_failure_up, bool_t expect_auth_failure_down ) {
if (!linphone_factory_is_database_storage_available(linphone_factory_get())) {
ms_warning("Test skipped, database storage is not available");
return;
......@@ -669,6 +669,15 @@ void transfer_message_base3(LinphoneCoreManager* marie, LinphoneCoreManager* pau
linphone_chat_message_send(msg);
if (expect_auth_failure_up) {
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageNotDelivered,1));
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered, 0, int, "%d");
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageFileTransferError, 1, int, "%d");
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageFileTransferDone, 0, int, "%d");
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,0, int, "%d");
goto end;
}
if (upload_error) {
int chat_room_size = 0;
bctbx_list_t *history;
......@@ -746,6 +755,13 @@ void transfer_message_base3(LinphoneCoreManager* marie, LinphoneCoreManager* pau
bc_free(receive_filepath);
}
linphone_chat_message_download_file(recv_msg);
if (expect_auth_failure_down) {
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneMessageFileTransferError, 1));
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,0, int, "%d");
goto end;
}
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageFileTransferInProgress, 1, int, "%d");
if (download_error) {
......@@ -861,7 +877,7 @@ static void transfer_message_tls_client_auth(void) {
FALSE, FALSE,
FALSE, FALSE,
FALSE,
-1, FALSE, FALSE, file_transfer_url_tls_client_auth);
-1, FALSE, FALSE, file_transfer_url_tls_client_auth, FALSE, FALSE);
// Give some time for IMDN's 200 OK to be received so it doesn't leak
wait_for_until(pauline->lc, marie->lc, NULL, 0, 1000);
......@@ -870,6 +886,91 @@ static void transfer_message_tls_client_auth(void) {
}
}
static void transfer_message_digest_auth_arg(const char *server_url, bool_t auth_info_failure_up, bool_t auth_info_failure_down) {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
// enable imdn (otherwise transfer_message_base3 is unhappy)
linphone_config_set_int(linphone_core_get_config(pauline->lc), "sip", "deliver_imdn", 1);
linphone_config_set_int(linphone_core_get_config(marie->lc), "sip", "deliver_imdn", 1);
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie->lc));
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline->lc));
// either up or down are set to fail, not both as up would stop the transfer anyway
LinphoneAuthInfo* good_auth_info=NULL;
LinphoneAuthInfo* wrong_auth_info=NULL;
if (auth_info_failure_up) {
// set wrong credentials for pauline (message sender)
good_auth_info=linphone_auth_info_clone(linphone_core_find_auth_info(pauline->lc,NULL,linphone_address_get_username(pauline->identity),NULL));
wrong_auth_info=linphone_auth_info_clone(good_auth_info);
linphone_auth_info_set_password(wrong_auth_info, "passecretdutout");
linphone_core_clear_all_auth_info(pauline->lc);
linphone_core_add_auth_info(pauline->lc,wrong_auth_info);
}
if (auth_info_failure_down) {
// set wrong credentials for marie (message receiver)
good_auth_info=linphone_auth_info_clone(linphone_core_find_auth_info(marie->lc,NULL,linphone_address_get_username(marie->identity),NULL));
wrong_auth_info=linphone_auth_info_clone(good_auth_info);
linphone_auth_info_set_password(wrong_auth_info, "passecretdutout");
linphone_core_clear_all_auth_info(marie->lc);
linphone_core_add_auth_info(marie->lc,wrong_auth_info);
}
transfer_message_base3(marie, pauline,
FALSE, FALSE,
FALSE, FALSE,
FALSE,
-1, FALSE, FALSE, server_url, auth_info_failure_up, auth_info_failure_down);
if (auth_info_failure_up) {
// to make sure unregister will work
linphone_core_clear_all_auth_info(pauline->lc);
linphone_core_add_auth_info(pauline->lc,good_auth_info);
linphone_auth_info_unref(good_auth_info);
linphone_auth_info_unref(wrong_auth_info);
}
if (auth_info_failure_down) {
// to make sure unregister will work
linphone_core_clear_all_auth_info(marie->lc);
linphone_core_add_auth_info(marie->lc,good_auth_info);
linphone_auth_info_unref(good_auth_info);
linphone_auth_info_unref(wrong_auth_info);
}
// Give some time for IMDN's 200 OK to be received so it doesn't leak
wait_for_until(pauline->lc, marie->lc, NULL, 0, 1000);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(marie);
}
}
static void transfer_message_digest_auth(void) {
transfer_message_digest_auth_arg(file_transfer_url_digest_auth, FALSE, FALSE);
}
static void transfer_message_digest_auth_fail_up(void) {
transfer_message_digest_auth_arg(file_transfer_url_digest_auth, TRUE, FALSE);
}
static void transfer_message_digest_auth_fail_down(void) {
transfer_message_digest_auth_arg(file_transfer_url_digest_auth, FALSE, TRUE);
}
static void transfer_message_digest_auth_any_domain(void) {
transfer_message_digest_auth_arg(file_transfer_url_digest_auth_any_domain, FALSE, FALSE);
}
static void transfer_message_digest_auth_fail_any_domain_up(void) {
transfer_message_digest_auth_arg(file_transfer_url_digest_auth_any_domain, TRUE, FALSE);
}
static void transfer_message_digest_auth_fail_any_domain_down(void) {
transfer_message_digest_auth_arg(file_transfer_url_digest_auth_any_domain, FALSE, TRUE);
}
void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pauline, bool_t upload_error, bool_t download_error,
bool_t use_file_body_handler_in_upload, bool_t use_file_body_handler_in_download, bool_t download_from_history,
int auto_download, bool_t two_files, bool_t legacy) {
......@@ -877,7 +978,7 @@ void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pau
upload_error, download_error,
use_file_body_handler_in_upload, use_file_body_handler_in_download,
download_from_history,
auto_download, two_files, legacy, file_transfer_url);
auto_download, two_files, legacy, file_transfer_url, FALSE, FALSE);
}
void transfer_message_base(
......@@ -3347,6 +3448,12 @@ test_t message_tests[] = {
TEST_NO_TAG("Transfer using external body URL 2", file_transfer_using_external_body_url_2),
TEST_NO_TAG("Transfer using external body URL 404", file_transfer_using_external_body_url_404),
TEST_NO_TAG("Transfer message - file transfer server authenticates client using certificate", transfer_message_tls_client_auth),
TEST_NO_TAG("Transfer message - file transfer server authenticates client using digest auth", transfer_message_digest_auth),
TEST_NO_TAG("Transfer message - file transfer server authenticates client using digest auth server accepting multiple auth domain", transfer_message_digest_auth_any_domain),
TEST_NO_TAG("Transfer message - file transfer server authenticates client using digest auth - upload auth fail", transfer_message_digest_auth_fail_up),
TEST_NO_TAG("Transfer message - file transfer server authenticates client using digest auth - download auth fail", transfer_message_digest_auth_fail_down),
TEST_NO_TAG("Transfer message - file transfer server authenticates client using digest auth server accepting multiple auth domain - upload auth fail", transfer_message_digest_auth_fail_any_domain_up),
TEST_NO_TAG("Transfer message - file transfer server authenticates client using digest auth server accepting multiple auth domain - download auth fail", transfer_message_digest_auth_fail_any_domain_down),
TEST_NO_TAG("Text message denied", text_message_denied),
#ifdef HAVE_ADVANCED_IM
TEST_NO_TAG("IsComposing notification", is_composing_notification),
......
......@@ -59,8 +59,10 @@ const char* pure_sha256_user="pure_sha256_user";
const char* test_password="secret";
const char* test_route="sip2.linphone.org";
const char *userhostsfile = "tester_hosts";
const char *file_transfer_url="https://transfer.example.org:9444/http-file-transfer-server/hft.php";
const char *file_transfer_url_tls_client_auth="https://transfer.example.org:9445/http-file-transfer-server/hft.php";
const char *file_transfer_url="https://transfer.example.org:9444/flexisip-http-file-transfer-server/hft.php";
const char *file_transfer_url_tls_client_auth="https://transfer.example.org:9445/flexisip-http-file-transfer-server/hft.php";
const char *file_transfer_url_digest_auth="https://transfer.example.org:9446/flexisip-http-file-transfer-server/hft.php";
const char *file_transfer_url_digest_auth_any_domain="https://transfer.example.org:9447/flexisip-http-file-transfer-server/hft.php";
// These lime server authenticate user using Digest auth only on sip.example.org domain
const char *lime_server_c25519_url="https://lime.wildcard1.linphone.org:8443/lime-server-c25519/lime-server.php";
const char *lime_server_c448_url="https://lime.wildcard1.linphone.org:8443/lime-server-c448/lime-server.php";
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment