Commit 0eef5c5e authored by jehan's avatar jehan

rework behavior for 403/401/407 auth failure to avoid loop and make sure retry are always done

parent be079dc8
......@@ -57,7 +57,7 @@ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *useri
return obj;
}
static LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){
LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){
LinphoneAuthInfo *obj=ms_new0(LinphoneAuthInfo,1);
if (ai->username) obj->username=ms_strdup(ai->username);
if (ai->userid) obj->userid=ms_strdup(ai->userid);
......
......@@ -116,8 +116,7 @@ void sal_process_authentication(SalOp *op) {
belle_sip_auth_event_t* auth_event;
belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction);
sal_add_pending_auth(op->base.root,op);
if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) {
new_request = belle_sip_dialog_create_request_from(op->dialog,initial_request);
if (!new_request)
......@@ -142,6 +141,8 @@ void sal_process_authentication(SalOp *op) {
sal_remove_pending_auth(op->base.root,op);
}else {
ms_message("No auth info found for [%s]",sal_op_get_from(op));
sal_add_pending_auth(op->base.root,op);
if (is_within_dialog) {
belle_sip_object_unref(new_request);
}
......@@ -326,15 +327,25 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
belle_sip_object_unref(op->pending_auth_transaction);
op->pending_auth_transaction=NULL;
}
op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction);
sal_process_authentication(op);
return;
if (++op->auth_requests > 2) {
ms_warning("Auth info cannot be found for op [%s] after 2 attempts, giving up",sal_op_get_from(op));
op->base.root->callbacks.auth_failure(op,op->auth_info);
sal_remove_pending_auth(op->base.root,op);
} else {
op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction);
sal_process_authentication(op);
return;
}
}
break;
case 403:
if (op->auth_info) op->base.root->callbacks.auth_failure(op,op->auth_info);
break;
}
if (response_code !=401 && response_code !=407 && response_code !=403) {
/*not an auth request*/
op->auth_requests=0;
}
op->callbacks.process_response_event(op,event);
} else {
ms_error("Unhandled event response [%p]",event);
......
......@@ -98,6 +98,7 @@ struct SalOp{
bool_t sdp_offering;
bool_t call_released;
bool_t manual_refresher;
int auth_requests; /*number of auth requested for this op*/
};
......
......@@ -63,7 +63,7 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher
if (op->auth_info) {
/*add pending auth*/
sal_add_pending_auth(op->base.root,op);
if (status_code==403)
if (status_code==403 || status_code==401 || status_code==407 )
op->base.root->callbacks.auth_failure(op,op->auth_info);
}
}
......
......@@ -918,6 +918,13 @@ typedef struct _LinphoneAuthInfo LinphoneAuthInfo;
LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid,
const char *passwd, const char *ha1,const char *realm, const char *domain);
/**
* @addtogroup authentication
* Instanciate a new auth info with values from source
* @param source auth info object to be cloned
* @return newly created auth info
*/
LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo* source);
LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd);
LINPHONE_PUBLIC void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username);
LINPHONE_PUBLIC void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid);
......
......@@ -1479,6 +1479,43 @@ static void call_established_with_rejected_reinvite_with_error(void) {
linphone_core_manager_destroy(pauline);
}
static void call_rejected_because_wrong_credentials_with_params(const char* user_agent) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneAuthInfo* good_auth_info=linphone_auth_info_clone((LinphoneAuthInfo*)(linphone_core_get_auth_info_list(marie->lc)->data));
LinphoneAuthInfo* wrong_auth_info=linphone_auth_info_clone(good_auth_info);
if (user_agent) {
linphone_core_set_user_agent(marie->lc,user_agent,NULL);
}
linphone_core_clear_all_auth_info(marie->lc);
CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(marie->lc,marie->identity));
CU_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_auth_info_requested,1));
linphone_auth_info_set_passwd(wrong_auth_info,"passecretdutout");
/*automatically re-inititae the call*/
linphone_core_add_auth_info(marie->lc,wrong_auth_info);
CU_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneCallError,1));
CU_ASSERT_EQUAL(marie->stat.number_of_auth_info_requested,2);
/*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_core_manager_destroy(marie);
}
static void call_rejected_because_wrong_credentials() {
call_rejected_because_wrong_credentials_with_params(NULL);
}
static void call_rejected_without_403_because_wrong_credentials() {
call_rejected_because_wrong_credentials_with_params("tester-no-403");
}
#ifdef VIDEO_ENABLED
#endif
......@@ -1511,6 +1548,8 @@ test_t call_tests[] = {
{ "SRTP ice call", srtp_ice_call },
#endif
{ "Call with privacy", call_with_privacy },
{ "Call rejected because of wrong credential", call_rejected_because_wrong_credentials},
{ "Call rejected without 403 because of wrong credential", call_rejected_without_403_because_wrong_credentials},
{ "Simple conference", simple_conference },
{ "Simple call transfer", simple_call_transfer },
{ "Unattended call transfer", unattended_call_transfer },
......
......@@ -86,9 +86,6 @@ ban-duration=60
# Default value: 20
packets-limit=20
# Maximal amount of simultaneous connections to accept.
# Default value: 1000
maximum-connections=1000
##
## The NatHelper module executes small tasks to make SIP work smoothly
......@@ -123,6 +120,9 @@ contact-verified-param=verified
# Default value: false
enabled=true
no-403=user-agent contains 'tester-no-403'
# A request/response enters module if the boolean filter evaluates
# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain
# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org')
......@@ -345,59 +345,7 @@ generated-contact-route=
# Default value:
generated-contact-expected-realm=
##
## This module performs push notifications
##
[module::PushNotification]
# Indicate whether the module is activated.
# Default value: false
enabled=false
# A request/response enters module if the boolean filter evaluates
# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain
# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org')
# && (user-agent == 'Linphone v2')
# Default value:
filter=
# Number of second to wait before sending a push notification to
# device(if <=0 then disabled)
# Default value: 5
timeout=5
# Maximum number of notifications queued for each client
# Default value: 10
max-queue-size=10
# Enable push notification for apple devices
# Default value: true
apple=true
# Path to directory where to find Apple Push Notification service
# certificates. They should bear the appid of the application, suffixed
# by the release mode and .pem extension. For example: org.linphone.dev.pem
# org.linphone.prod.pem com.somephone.dev.pem etc... The files should
# be .pem format, and made of certificate followed by private key.
# Default value: /etc/flexisip/apn
apple-certificate-dir=/etc/flexisip/apn
# Enable push notification for android devices
# Default value: true
google=true
# List of couple projectId:ApiKey for each android project which
# support push notifications
# Default value:
google-projects-api-keys=
##
## The purpose of the ContactRouteInserter module is to masquerade
## the contact header of incoming registers that are not handled
## locally (think about flexisip used as a SBC gateway) in such a
## way that it is then possible to route back outgoing invites to
## the original address. It is a kind of similar mechanism as Record-Route,
## but for REGISTER.
##
[module::ContactRouteInserter]
# Indicate whether the module is activated.
# Default value: true
......
......@@ -70,17 +70,13 @@ LinphoneAddress * create_linphone_address(const char * domain) {
return addr;
}
void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
stats* counters;
LinphoneAuthInfo *info;
ms_message("Auth info requested for user id [%s] at realm [%s]\n"
,username
,realm);
counters = get_stats(lc);
counters->number_of_auth_info_requested++;
info=linphone_auth_info_new(test_username,NULL,test_password,NULL,realm,domain); /*create authentication structure from identity*/
linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/
}
......
......@@ -198,7 +198,6 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess
void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room);
void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg);
void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain);
void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state);
void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state);
void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content);
......
......@@ -22,6 +22,26 @@
#include "private.h"
#include "liblinphone_tester.h"
static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
stats* counters;
ms_message("Auth info requested for user id [%s] at realm [%s]\n"
,username
,realm);
counters = get_stats(lc);
counters->number_of_auth_info_requested++;
}
static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
LinphoneAuthInfo *info;
auth_info_requested2(lc,realm,username,domain);
info=linphone_auth_info_new(test_username,NULL,test_password,NULL,realm,domain); /*create authentication structure from identity*/
linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/
}
static LinphoneCoreManager* create_lcm_with_auth(unsigned int with_auth) {
LinphoneCoreManager* mgr=linphone_core_manager_new(NULL);
......@@ -108,7 +128,8 @@ static void register_with_refresh_base_3(LinphoneCore* lc
linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/
}
}
if (linphone_proxy_config_get_error(proxy_cfg) == LinphoneReasonBadCredentials)
if (linphone_proxy_config_get_error(proxy_cfg) == LinphoneReasonBadCredentials
|| (counters->number_of_auth_info_requested>2 &&linphone_proxy_config_get_error(proxy_cfg) == LinphoneReasonUnauthorized)) /*no need to continue if auth cannot be found*/
break; /*no need to continue*/
ms_usleep(100000);
}
......@@ -261,6 +282,8 @@ static void authenticated_register_with_no_initial_credentials(){
mgr = linphone_core_manager_new(NULL);
mgr->lc->vtable.auth_info_requested=auth_info_requested;
counters= get_stats(mgr->lc);
counters->number_of_auth_info_requested=0;
register_with_refresh(mgr,FALSE,auth_domain,route);
......@@ -268,14 +291,6 @@ static void authenticated_register_with_no_initial_credentials(){
linphone_core_manager_destroy(mgr);
}
static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
stats* counters;
ms_message("Auth info requested for user id [%s] at realm [%s]\n"
,username
,realm);
counters = get_stats(lc);
counters->number_of_auth_info_requested++;
}
static void authenticated_register_with_late_credentials(){
LinphoneCoreManager *mgr;
......@@ -286,10 +301,10 @@ static void authenticated_register_with_late_credentials(){
sprintf(route,"sip:%s",test_route);
mgr = linphone_core_manager_new(NULL);
mgr->lc->vtable.auth_info_requested=auth_info_requested2;
counters = get_stats(mgr->lc);
register_with_refresh_base_2(mgr->lc,FALSE,auth_domain,route,TRUE,transport);
CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1);
CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,2); /*1 registration error = 2 auth requested*/
linphone_core_manager_destroy(mgr);
}
......@@ -306,10 +321,10 @@ static void authenticated_register_with_wrong_late_credentials(){
sprintf(route,"sip:%s",test_route);
mgr = linphone_core_manager_new(NULL);
mgr->lc->vtable.auth_info_requested=auth_info_requested2;
counters = get_stats(mgr->lc);
register_with_refresh_base_3(mgr->lc,FALSE,auth_domain,route,TRUE,transport,LinphoneRegistrationFailed);
CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,2);
CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,3);
CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,2);
CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,2);
test_password=saved_test_passwd;
......@@ -317,7 +332,7 @@ static void authenticated_register_with_wrong_late_credentials(){
linphone_core_manager_destroy(mgr);
}
static void authenticated_register_with_wrong_credentials(){
static void authenticated_register_with_wrong_credentials_with_params(const char* user_agent) {
LinphoneCoreManager *mgr;
stats* counters;
LCSipTransports transport = {5070,5070,0,5071};
......@@ -327,15 +342,28 @@ static void authenticated_register_with_wrong_credentials(){
sprintf(route,"sip:%s",test_route);
mgr=linphone_core_manager_new(NULL);
mgr->lc->vtable.auth_info_requested=auth_info_requested2;
sal_set_refresher_retry_after(mgr->lc->sal,500);
if (user_agent) {
linphone_core_set_user_agent(mgr->lc,user_agent,NULL);
}
linphone_core_add_auth_info(mgr->lc,info); /*add wrong authentication info to LinphoneCore*/
counters = get_stats(mgr->lc);
register_with_refresh_base_3(mgr->lc,TRUE,auth_domain,route,TRUE,transport,LinphoneRegistrationFailed);
CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1);
register_with_refresh_base_3(mgr->lc,TRUE,auth_domain,route,FALSE,transport,LinphoneRegistrationFailed);
//CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,3); register_with_refresh_base_3 does not alow to precisely check number of number_of_auth_info_requested
/*wait for retry*/
CU_ASSERT_TRUE(wait_for(mgr->lc,mgr->lc,&counters->number_of_auth_info_requested,4));
CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,1);
linphone_core_manager_destroy(mgr);
}
static void authenticated_register_with_wrong_credentials() {
authenticated_register_with_wrong_credentials_with_params(NULL);
}
static void authenticated_register_with_wrong_credentials_without_403() {
authenticated_register_with_wrong_credentials_with_params("tester-no-403");
}
static LinphoneCoreManager* configure_lcm(void) {
LinphoneCoreManager *mgr=linphone_core_manager_new( "multi_account_lrc");
stats *counters=&mgr->stat;
......@@ -611,6 +639,7 @@ test_t register_tests[] = {
{ "Ha1 authenticated register", ha1_authenticated_register },
{ "Digest auth without initial credentials", authenticated_register_with_no_initial_credentials },
{ "Digest auth with wrong credentials", authenticated_register_with_wrong_credentials },
{ "Digest auth with wrong credentials without 403", authenticated_register_with_wrong_credentials_without_403},
{ "Authenticated register with wrong late credentials", authenticated_register_with_wrong_late_credentials},
{ "Authenticated register with late credentials", authenticated_register_with_late_credentials },
{ "Register with refresh", simple_register_with_refresh },
......
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