Reuse previous nonce if outbound proxy realm is set to avoid reauthentication

parent b3012e59
......@@ -62,11 +62,12 @@ BELLESIP_EXPORT void belle_sip_provider_clean_channels(belle_sip_provider_t *p);
* @param request to be updated
* @param resp response to take authentication values from, might be NULL
* @param from_uri optional - an uri to use instead of the from of the request, which can be anonymous.
* @param auth_infos A newly allocated belle_sip_auth_info_t object is added to this list. These object contains useful information like realm and username.
* @param auth_infos optional - A newly allocated belle_sip_auth_info_t object is added to this list. These object contains useful information like realm and username.
* @param realm optional - If an outbound proxy realm is used, nounce can be reused from previous request to avoid re-authentication.
* @returns 0 in case of success,
*
**/
BELLESIP_EXPORT int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_request_t* request,belle_sip_response_t *resp, belle_sip_uri_t *from_uri, belle_sip_list_t** auth_infos);
BELLESIP_EXPORT int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_request_t* request,belle_sip_response_t *resp, belle_sip_uri_t *from_uri, belle_sip_list_t** auth_infos, const char* realm);
/**
* Can be used to simulate network recv error, for tests.
......
......@@ -72,6 +72,16 @@ BELLESIP_EXPORT int belle_sip_refresher_get_retry_after(const belle_sip_refreshe
*/
BELLESIP_EXPORT void belle_sip_refresher_set_retry_after(belle_sip_refresher_t* refresher, int delay_ms);
/**
* returns realm of the outbound proxy used for authentication, if any
*/
BELLESIP_EXPORT const char* belle_sip_refresher_get_realm(const belle_sip_refresher_t* refresher);
/**
* Realm of the outbound proxy used for authentication, if any
*/
BELLESIP_EXPORT void belle_sip_refresher_set_realm(belle_sip_refresher_t* refresher, const char* realm);
/**
* get current client transaction
* @param refresher object
......
......@@ -78,9 +78,10 @@ BELLESIP_EXPORT belle_sip_refresher_t* belle_sip_client_transaction_create_refre
* <br>This function, update cseq, put route set and try to fill authorization headers. Initial request is not cloned.
* @param transaction . must be in state completed
* @param auth_infos if auth infos cannot be added for an authenticate header,
* @param realm optional - If an outbound proxy realm is used, digestion authentication can be optimized.
* a newly allocated belle_sip_auth_info_t object is added to this list. These object contains useful information like realm and username. May be NULL
* */
BELLESIP_EXPORT belle_sip_request_t* belle_sip_client_transaction_create_authenticated_request(belle_sip_client_transaction_t *t,belle_sip_list_t** auth_infos);
BELLESIP_EXPORT belle_sip_request_t* belle_sip_client_transaction_create_authenticated_request(belle_sip_client_transaction_t *t,belle_sip_list_t** auth_infos,const char* realm);
#define BELLE_SIP_TRANSACTION(t) BELLE_SIP_CAST(t,belle_sip_transaction_t)
#define BELLE_SIP_SERVER_TRANSACTION(t) BELLE_SIP_CAST(t,belle_sip_server_transaction_t)
......
......@@ -28,6 +28,7 @@ typedef struct authorization_context {
const char* nonce;
const char* qop;
const char* opaque;
const char* user_id;
int nonce_count;
int is_proxy;
}authorization_context_t;
......@@ -37,6 +38,7 @@ GET_SET_STRING(authorization_context,nonce)
GET_SET_STRING(authorization_context,qop)
GET_SET_STRING(authorization_context,scheme)
GET_SET_STRING(authorization_context,opaque)
GET_SET_STRING(authorization_context,user_id)
GET_SET_INT(authorization_context,nonce_count,int)
static authorization_context_t* belle_sip_authorization_create(belle_sip_header_call_id_t* call_id) {
authorization_context_t* result = malloc(sizeof(authorization_context_t));
......@@ -51,6 +53,7 @@ static void belle_sip_authorization_destroy(authorization_context_t* object) {
DESTROY_STRING(object,nonce);
DESTROY_STRING(object,qop);
DESTROY_STRING(object,opaque);
DESTROY_STRING(object,user_id);
belle_sip_object_unref(object->callid);
belle_sip_free(object);
}
......@@ -136,11 +139,17 @@ static void belle_sip_provider_dispatch_request(belle_sip_provider_t* prov, bell
}
}
static belle_sip_list_t* belle_sip_provider_get_auth_context_by_call_id(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id);
static belle_sip_list_t* belle_sip_provider_get_auth_context_by_realm_or_call_id(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id,belle_sip_uri_t *from_uri,const char* realm);
static void belle_sip_provider_dispatch_response(belle_sip_provider_t* prov, belle_sip_response_t *msg){
static int belle_sip_auth_context_find_by_nonce(const void* elem, const void* nonce_value){
authorization_context_t * a = (authorization_context_t*)elem;
return strcmp(a->nonce, (const char*)nonce_value);
}
static void belle_sip_provider_dispatch_response(belle_sip_provider_t* p, belle_sip_response_t *msg){
belle_sip_client_transaction_t *t;
t=belle_sip_provider_find_matching_client_transaction(prov,msg);
t=belle_sip_provider_find_matching_client_transaction(p,msg);
/*good opportunity to cleanup auth context if answer = 401|407|403*/
......@@ -148,13 +157,20 @@ static void belle_sip_provider_dispatch_response(belle_sip_provider_t* prov, bel
case 401:
case 403:
case 407: {
belle_sip_header_call_id_t* call_id=call_id = belle_sip_message_get_header_by_type(msg,belle_sip_header_call_id_t);
belle_sip_list_t* iterator;
belle_sip_list_t* head=belle_sip_provider_get_auth_context_by_call_id(prov,call_id);
for (iterator=head;iterator!=NULL;iterator=iterator->next){
prov->auth_contexts=belle_sip_list_remove(prov->auth_contexts,iterator->data);
const char* nonce = NULL;
belle_sip_message_t* req = BELLE_SIP_MESSAGE(belle_sip_transaction_get_request((belle_sip_transaction_t*)t));
belle_sip_header_authorization_t* authorization=BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_message_get_header_by_type(req, belle_sip_header_proxy_authorization_t));
if (authorization==NULL) authorization=belle_sip_message_get_header_by_type(req, belle_sip_header_authorization_t);
if (authorization!=NULL){
nonce = belle_sip_header_authorization_get_nonce(authorization);
if (nonce != NULL){
belle_sip_list_t * auth_context_with_nonce = NULL;
while ((auth_context_with_nonce = belle_sip_list_find_custom(p->auth_contexts, belle_sip_auth_context_find_by_nonce, nonce)) != NULL){
belle_sip_authorization_destroy(auth_context_with_nonce->data);
p->auth_contexts = belle_sip_list_delete_link(p->auth_contexts, auth_context_with_nonce);
}
}
}
belle_sip_list_free_with_data(head,(void (*)(void *))belle_sip_authorization_destroy);
}
}
/*
......@@ -169,11 +185,11 @@ static void belle_sip_provider_dispatch_response(belle_sip_provider_t* prov, bel
belle_sip_object_unref(t);
}else{
belle_sip_response_event_t event;
event.source=(belle_sip_object_t*)prov;
event.source=(belle_sip_object_t*)p;
event.client_transaction=NULL;
event.dialog=NULL;
event.response=msg;
BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_response_event,&event);
BELLE_SIP_PROVIDER_INVOKE_LISTENERS(p->listeners,process_response_event,&event);
}
}
......@@ -923,7 +939,7 @@ void belle_sip_provider_remove_server_transaction(belle_sip_provider_t *prov, be
}
static void authorization_context_fill_from_auth(authorization_context_t* auth_context,belle_sip_header_www_authenticate_t* authenticate) {
static void authorization_context_fill_from_auth(authorization_context_t* auth_context,belle_sip_header_www_authenticate_t* authenticate,belle_sip_uri_t *from_uri) {
authorization_context_set_realm(auth_context,belle_sip_header_www_authenticate_get_realm(authenticate));
if (auth_context->nonce && strcmp(belle_sip_header_www_authenticate_get_nonce(authenticate),auth_context->nonce)!=0) {
/*new nonce, resetting nounce_count*/
......@@ -933,45 +949,91 @@ static void authorization_context_fill_from_auth(authorization_context_t* auth_c
authorization_context_set_qop(auth_context,belle_sip_header_www_authenticate_get_qop_first(authenticate));
authorization_context_set_scheme(auth_context,belle_sip_header_www_authenticate_get_scheme(authenticate));
authorization_context_set_opaque(auth_context,belle_sip_header_www_authenticate_get_opaque(authenticate));
authorization_context_set_user_id(auth_context, from_uri?belle_sip_uri_get_user(from_uri):NULL);
if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(authenticate,belle_sip_header_proxy_authenticate_t)) {
auth_context->is_proxy=1;
}
}
static belle_sip_list_t* belle_sip_provider_get_auth_context_by_call_id(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id) {
static belle_sip_list_t* belle_sip_provider_get_auth_context_by_realm_or_call_id(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id,belle_sip_uri_t *from_uri,const char* realm) {
belle_sip_list_t* auth_context_lst=NULL;
belle_sip_list_t* result=NULL;
authorization_context_t* auth_context;
for (auth_context_lst=p->auth_contexts;auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) {
auth_context=(authorization_context_t*)auth_context_lst->data;
if (belle_sip_header_call_id_equals(auth_context->callid,call_id) ) {
result=belle_sip_list_append(result,auth_context_lst->data);
}
}
/* According to the RFC3261 22.3, if the outbound proxy realm is set, we could reuse its nonce value:
* "If a UA receives a Proxy-Authenticate header field value in a 401/407
* response to a request with a particular Call-ID, it should
* incorporate credentials for that realm in all subsequent requests
* that contain the same Call-ID. These credentials MUST NOT be cached
* across dialogs; however, if a UA is configured with the realm of its
* local outbound proxy, when one exists, then the UA MAY cache
* credentials for that realm across dialogs."
*/
if (result == NULL){
const char * from_user=from_uri?belle_sip_uri_get_user(from_uri):NULL;
belle_sip_debug("belle_sip_provider_auth: no auth_context registered with [call_id=%s], looking for realm..."
, call_id?belle_sip_header_call_id_get_call_id(call_id):"(null)");
for (auth_context_lst=p->auth_contexts;auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) {
auth_context=(authorization_context_t*)auth_context_lst->data;
belle_sip_debug("belle_sip_provider_auth: \t[realm=%s] [user_id=%s] [call_id=%s]",
auth_context->realm?auth_context->realm:"(null)",
auth_context->user_id?auth_context->user_id:"(null)",
auth_context->callid?belle_sip_header_call_id_get_call_id(auth_context->callid):"(null)"
);
/* We also verify that user matches in case of multi-account to avoid use nonce from another account. For a
* single user, from_uri user id and realm user id COULD be different but we assume here that this is not the case
* in order to avoid adding another field in auth_context struct.
**/
if ((realm && strcmp(auth_context->realm,realm)==0)
&& (from_user && auth_context->user_id && strcmp(auth_context->user_id,from_user)==0)) {
result=belle_sip_list_append(result,auth_context_lst->data);
belle_sip_debug("belle_sip_provider_auth: found a MATCHING realm auth_context!");
}
}
}
return result;
}
static void belle_sip_provider_update_or_create_auth_context(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id,belle_sip_header_www_authenticate_t* authenticate) {
belle_sip_list_t* auth_context_lst = belle_sip_provider_get_auth_context_by_call_id(p,call_id);
static void belle_sip_provider_update_or_create_auth_context(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id,belle_sip_header_www_authenticate_t* authenticate,belle_sip_uri_t *from_uri,const char* realm) {
belle_sip_list_t* auth_context_lst = NULL;
authorization_context_t* auth_context;
for (;auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) {
auth_context= (authorization_context_t*)auth_context_lst->data;
for (auth_context_lst=belle_sip_provider_get_auth_context_by_realm_or_call_id(p,call_id,from_uri,realm);auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) {
auth_context=(authorization_context_t*)auth_context_lst->data;
if (strcmp(auth_context->realm,belle_sip_header_www_authenticate_get_realm(authenticate))==0) {
authorization_context_fill_from_auth(auth_context,authenticate);
authorization_context_fill_from_auth(auth_context,authenticate,from_uri);
if (auth_context_lst) belle_sip_free(auth_context_lst);
return; /*only one realm is supposed to be found for now*/
}
}
/*no auth context found, creating one*/
auth_context=belle_sip_authorization_create(call_id);
authorization_context_fill_from_auth(auth_context,authenticate);
belle_sip_debug("belle_sip_provider_auth: no matching auth context, creating one for [realm=%s][user_id=%s][call_id=%s]"
, realm?realm:"(null)"
, from_uri?belle_sip_uri_get_user(from_uri):"(null)"
, call_id?belle_sip_header_call_id_get_call_id(call_id):"(null)");
authorization_context_fill_from_auth(auth_context,authenticate,from_uri);
p->auth_contexts=belle_sip_list_append(p->auth_contexts,auth_context);
if (auth_context_lst) belle_sip_free(auth_context_lst);
return;
}
int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_request_t* request, belle_sip_response_t *resp,
belle_sip_uri_t *from_uri, belle_sip_list_t** auth_infos) {
belle_sip_uri_t *from_uri, belle_sip_list_t** auth_infos, const char* realm) {
belle_sip_header_call_id_t* call_id;
belle_sip_list_t* auth_context_iterator;
belle_sip_list_t* authenticate_lst;
......@@ -991,7 +1053,8 @@ int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_requ
return-1;
}
request_method=belle_sip_request_get_method(request);
/*22 Usage of HTTP Authentication
/*22 Usage of HTTP Authentication
22.1 Framework
While a server can legitimately challenge most SIP requests, there
are two requests defined by this document that require special
......@@ -1017,6 +1080,12 @@ int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_requ
belle_sip_debug("no authorization header needed for method [%s]",request_method);
return 0;
}
if (from_uri==NULL){
from = belle_sip_message_get_header_by_type(request,belle_sip_header_from_t);
from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)from);
}
/*get authenticates value from response*/
if (resp) {
belle_sip_list_t *it;
......@@ -1028,18 +1097,21 @@ int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_requ
/*update auth contexts with authenticate headers from response*/
for (it=authenticate_lst;it!=NULL;it=it->next) {
authenticate=BELLE_SIP_HEADER_WWW_AUTHENTICATE(it->data);
belle_sip_provider_update_or_create_auth_context(p,call_id,authenticate);
belle_sip_provider_update_or_create_auth_context(p,call_id,authenticate,from_uri,realm);
}
belle_sip_list_free(authenticate_lst);
}
/*put authorization header if passwd found*/
call_id = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_call_id_t);
if (from_uri==NULL){
from = belle_sip_message_get_header_by_type(request,belle_sip_header_from_t);
from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)from);
}
head=belle_sip_provider_get_auth_context_by_call_id(p,call_id);
belle_sip_debug("belle_sip_provider_auth: looking an auth context for [method=%s][realm=%s][user_id=%s][call_id=%s]"
, request_method
, realm?realm:"(null)"
, from_uri?belle_sip_uri_get_user(from_uri):"(null)"
, call_id?belle_sip_header_call_id_get_call_id(call_id):"(null)"
);
head=belle_sip_provider_get_auth_context_by_realm_or_call_id(p,call_id,from_uri,realm);
/*we assume there no existing auth headers*/
for (auth_context_iterator=head;auth_context_iterator!=NULL;auth_context_iterator=auth_context_iterator->next) {
/*clear auth info*/
......@@ -1055,7 +1127,8 @@ int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_requ
belle_sip_auth_event_set_userid(auth_event,(const char*)auth_event->username);
}
belle_sip_message("Auth info found for [%s] realm [%s]",auth_event->userid,auth_event->realm);
if (auth_context->is_proxy) {
if (auth_context->is_proxy ||
(!belle_sip_header_call_id_equals(call_id,auth_context->callid)&&realm&&strcmp(realm,auth_context->realm)==0&&from_uri&&strcmp(auth_event->username,belle_sip_uri_get_user(from_uri))==0)) {
authorization=BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_header_proxy_authorization_new());
} else {
authorization=belle_sip_header_authorization_new();
......@@ -1067,8 +1140,11 @@ int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_requ
belle_sip_header_authorization_set_qop(authorization,auth_context->qop);
belle_sip_header_authorization_set_opaque(authorization,auth_context->opaque);
belle_sip_header_authorization_set_uri(authorization,(belle_sip_uri_t*)belle_sip_request_get_uri(request));
if (auth_context->qop)
belle_sip_header_authorization_set_nonce_count(authorization,++auth_context->nonce_count);
if (auth_context->qop){
++auth_context->nonce_count;
belle_sip_header_authorization_set_nonce_count(authorization,auth_context->nonce_count);
}
if (auth_event->ha1) {
ha1=auth_event->ha1;
} else {
......
......@@ -39,6 +39,7 @@ struct belle_sip_refresher {
belle_sip_refresher_listener_t listener;
belle_sip_source_t* timer;
belle_sip_client_transaction_t* transaction;
char* realm;
int target_expires;
int obtained_expires;
belle_sip_refresher_state_t state;
......@@ -314,6 +315,7 @@ static void destroy(belle_sip_refresher_t *refresher){
belle_sip_provider_remove_internal_sip_listener(refresher->transaction->base.provider,BELLE_SIP_LISTENER(refresher));
belle_sip_object_unref(refresher->transaction);
refresher->transaction=NULL;
if (refresher->realm) belle_sip_free(refresher->realm);
if (refresher->auth_events) refresher->auth_events=belle_sip_list_free_with_data(refresher->auth_events,(void (*)(void*))belle_sip_auth_event_destroy);
}
......@@ -379,7 +381,7 @@ static int belle_sip_refresher_refresh_internal(belle_sip_refresher_t* refresher
cseq=belle_sip_message_get_header_by_type(request,belle_sip_header_cseq_t);
belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1);
} else {
request=belle_sip_client_transaction_create_authenticated_request(refresher->transaction,auth_infos);
request=belle_sip_client_transaction_create_authenticated_request(refresher->transaction,auth_infos,refresher->realm);
}
if (requri){
/*case where we are redirected*/
......@@ -401,7 +403,7 @@ static int belle_sip_refresher_refresh_internal(belle_sip_refresher_t* refresher
belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header));
}
}
belle_sip_provider_add_authorization(prov,request,old_response,NULL,auth_infos);
belle_sip_provider_add_authorization(prov,request,old_response,NULL,auth_infos,refresher->realm);
} else {
belle_sip_error("Unexpected dialog state [%s] for dialog [%p], cannot refresh [%s]"
,belle_sip_dialog_state_to_string(belle_sip_dialog_get_state(dialog))
......@@ -658,6 +660,21 @@ int belle_sip_refresher_get_retry_after(const belle_sip_refresher_t* refresher){
void belle_sip_refresher_set_retry_after(belle_sip_refresher_t* refresher, int delay_ms) {
refresher->retry_after=delay_ms;
}
const char* belle_sip_refresher_get_realm(const belle_sip_refresher_t* refresher){
return refresher->realm;
}
void belle_sip_refresher_set_realm(belle_sip_refresher_t* refresher, const char* realm) {
if (refresher->realm){
belle_sip_free(refresher->realm);
refresher->realm = NULL;
}
if (realm!=NULL){
refresher->realm=belle_sip_strdup(realm);
}
}
const belle_sip_client_transaction_t* belle_sip_refresher_get_transaction(const belle_sip_refresher_t* refresher) {
return refresher->transaction;
}
......
......@@ -544,7 +544,7 @@ belle_sip_refresher_t* belle_sip_client_transaction_create_refresher(belle_sip_c
return belle_sip_refresher_new(t);
}
belle_sip_request_t* belle_sip_client_transaction_create_authenticated_request(belle_sip_client_transaction_t *t,belle_sip_list_t** auth_infos) {
belle_sip_request_t* belle_sip_client_transaction_create_authenticated_request(belle_sip_client_transaction_t *t,belle_sip_list_t** auth_infos,const char* realm) {
belle_sip_request_t* initial_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t));
belle_sip_request_t* req=belle_sip_request_clone_with_body(initial_request);
belle_sip_header_cseq_t* cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t);
......@@ -562,7 +562,7 @@ belle_sip_request_t* belle_sip_client_transaction_create_authenticated_request(b
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_PROXY_AUTHORIZATION);
/*put auth header*/
belle_sip_provider_add_authorization(t->base.provider,req,t->base.last_response,NULL,auth_infos);
belle_sip_provider_add_authorization(t->base.provider,req,t->base.last_response,NULL,auth_infos,realm);
return req;
}
......@@ -403,7 +403,7 @@ static void refresher_base_with_body(endpoint_t* client
} else {
CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.fourHundredOne,1,1000));
/*update cseq*/
req=belle_sip_client_transaction_create_authenticated_request(trans,NULL);
req=belle_sip_client_transaction_create_authenticated_request(trans,NULL,NULL);
belle_sip_object_unref(trans);
trans=belle_sip_provider_create_client_transaction(client->provider,req);
belle_sip_object_ref(trans);
......@@ -516,7 +516,7 @@ static void subscribe_test(void) {
CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.fourHundredOne,1,1000));
req=belle_sip_client_transaction_create_authenticated_request(trans,NULL);
req=belle_sip_client_transaction_create_authenticated_request(trans,NULL,NULL);
belle_sip_object_unref(trans);
trans=belle_sip_provider_create_client_transaction(client->provider,req);
belle_sip_object_ref(trans);
......
......@@ -75,18 +75,22 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
belle_sip_message("process_response_event [%i] [%s]"
,status=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event))
,belle_sip_response_get_reason_phrase(belle_sip_response_event_get_response(event)));
if (status==401) {
if (status==401){
belle_sip_header_cseq_t* cseq;
belle_sip_client_transaction_t *t;
belle_sip_uri_t *dest;
CU_ASSERT_NOT_EQUAL_FATAL(number_of_challenge,2);
// CU_ASSERT_NOT_EQUAL_FATAL(number_of_challenge,2);
CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_response_event_get_client_transaction(event)); /*require transaction mode*/
dest=belle_sip_client_transaction_get_route(belle_sip_response_event_get_client_transaction(event));
request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(belle_sip_response_event_get_client_transaction(event)));
cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CSEQ);
belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1);
CU_ASSERT_TRUE_FATAL(belle_sip_provider_add_authorization(prov,request,belle_sip_response_event_get_response(event),NULL,NULL));
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION);
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION);
CU_ASSERT_TRUE_FATAL(belle_sip_provider_add_authorization(prov,request,belle_sip_response_event_get_response(event),NULL,NULL,auth_domain));
t=belle_sip_provider_create_client_transaction(prov,request);
belle_sip_client_transaction_send_request_to(t,dest);
number_of_challenge++;
......@@ -236,9 +240,7 @@ void unregister_user(belle_sip_stack_t * stack
belle_sip_header_expires_set_expires(expires_header,0);
if (use_transaction){
belle_sip_client_transaction_t *t;
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_AUTHORIZATION);
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_PROXY_AUTHORIZATION);
belle_sip_provider_add_authorization(prov,req,NULL,NULL,NULL); /*just in case*/
belle_sip_provider_add_authorization(prov,req,NULL,NULL,NULL,NULL); /*just in case*/
t=belle_sip_provider_create_client_transaction(prov,req);
belle_sip_client_transaction_send_request(t);
}else belle_sip_provider_send_request(prov,req);
......@@ -559,6 +561,125 @@ static void register_dns_load_balancing(void) {
if (req) belle_sip_object_unref(req);
}
static void process_message_response_event(void *user_ctx, const belle_sip_response_event_t *event){
int status;
BELLESIP_UNUSED(user_ctx);
CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_response_event_get_response(event));
belle_sip_message("process_response_event [%i] [%s]"
,status=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event))
,belle_sip_response_get_reason_phrase(belle_sip_response_event_get_response(event)));
if (status >= 200){
is_register_ok=status;
belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack));
}
}
static belle_sip_request_t* send_message(belle_sip_request_t *initial_request, const char* realm){
int i;
int io_error_count=0;
belle_sip_request_t *message_request=NULL;
belle_sip_request_t *clone_request=NULL;
// belle_sip_header_authorization_t * h=NULL;
is_register_ok = 0;
message_request=belle_sip_request_create(
belle_sip_uri_parse("sip:sip.linphone.org;transport=tcp")
,"MESSAGE"
,belle_sip_provider_create_call_id(prov)
,belle_sip_header_cseq_create(22,"MESSAGE")
,belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(initial_request), belle_sip_header_from_t)
,belle_sip_header_to_parse("To: sip:marie@sip.linphone.org")
,belle_sip_header_via_new()
,70);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(message_request),BELLE_SIP_HEADER(belle_sip_header_expires_create(600)));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(message_request),BELLE_SIP_HEADER(belle_sip_header_contact_new()));
belle_sip_provider_add_authorization(prov,message_request,NULL,NULL,NULL,realm);
// h = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(message_request), belle_sip_header_authorization_t);
/*if a matching authorization was found, use it as a proxy authorization*/
// if (h != NULL){
// belle_sip_header_set_name(BELLE_SIP_HEADER(h), BELLE_SIP_PROXY_AUTHORIZATION);
// }
clone_request = (belle_sip_request_t*)belle_sip_object_ref(belle_sip_object_clone((belle_sip_object_t*)message_request));
belle_sip_client_transaction_send_request_to(belle_sip_provider_create_client_transaction(prov,message_request),NULL);
for(i=0; i<2 && io_error_count==0 &&is_register_ok==0;i++)
belle_sip_stack_sleep(stack,5000);
return clone_request;
}
static void reuse_nonce(void) {
belle_sip_request_t *register_request;
register_request=register_user_at_domain(stack, prov, "tcp",1,"marie","sip.linphone.org",NULL);
if (register_request) {
char * first_nonce_used;
belle_sip_header_authorization_t * h = NULL;
belle_sip_request_t *message_request;
listener_callbacks.process_dialog_terminated=process_dialog_terminated;
listener_callbacks.process_io_error=process_io_error;
listener_callbacks.process_request_event=process_request_event;
listener_callbacks.process_response_event=process_message_response_event;
listener_callbacks.process_timeout=process_timeout;
listener_callbacks.process_transaction_terminated=process_transaction_terminated;
listener_callbacks.process_auth_requested=process_auth_requested;
listener_callbacks.listener_destroyed=NULL;
listener=belle_sip_listener_create_from_callbacks(&listener_callbacks,NULL);
belle_sip_provider_add_sip_listener(prov,BELLE_SIP_LISTENER(listener));
/*currently only one nonce should have been used (the one for the REGISTER)*/
CU_ASSERT_EQUAL(belle_sip_list_size(prov->auth_contexts), 1);
/*this should reuse previous nonce*/
message_request=send_message(register_request, auth_domain);
CU_ASSERT_EQUAL(is_register_ok, 404);
h = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_message_get_header_by_type(
BELLE_SIP_MESSAGE(message_request), belle_sip_header_proxy_authorization_t
));
CU_ASSERT_PTR_NOT_NULL_FATAL(h);
CU_ASSERT_EQUAL(2, belle_sip_header_authorization_get_nonce_count(h));
first_nonce_used = belle_sip_strdup(belle_sip_header_authorization_get_nonce(h));
belle_sip_object_unref(message_request);
/*new nonce should be created when not using outbound proxy realm*/
message_request=send_message(register_request, NULL);
CU_ASSERT_EQUAL(is_register_ok, 407);
h = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_message_get_header_by_type(
BELLE_SIP_MESSAGE(message_request), belle_sip_header_proxy_authorization_t
));
CU_ASSERT_PTR_NULL_FATAL(h);
belle_sip_object_unref(message_request);
/*new nonce should be created here too*/
message_request=send_message(register_request, "wrongrealm");
CU_ASSERT_EQUAL(is_register_ok, 407);
h = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_message_get_header_by_type(
BELLE_SIP_MESSAGE(message_request), belle_sip_header_proxy_authorization_t
));
CU_ASSERT_PTR_NULL_FATAL(h);
belle_sip_object_unref(message_request);
/*first nonce created should be reused*/
message_request=send_message(register_request, auth_domain);
CU_ASSERT_EQUAL(is_register_ok, 404);
h = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_message_get_header_by_type(
BELLE_SIP_MESSAGE(message_request), belle_sip_header_proxy_authorization_t
));
CU_ASSERT_PTR_NOT_NULL_FATAL(h);
CU_ASSERT_EQUAL(3, belle_sip_header_authorization_get_nonce_count(h));
belle_sip_object_unref(message_request);
belle_sip_provider_remove_sip_listener(prov,BELLE_SIP_LISTENER(listener));
unregister_user(stack,prov,register_request,1);
belle_sip_object_unref(register_request);
belle_sip_free(first_nonce_used);
}
}
test_t register_tests[] = {
{ "Stateful UDP", stateful_register_udp },
......@@ -581,7 +702,8 @@ test_t register_tests[] = {
{ "TLS connection to TCP server", test_tls_to_tcp },
{ "Register with DNS SRV failover TCP", register_dns_srv_tcp },
{ "Register with DNS SRV failover TLS", register_dns_srv_tls },
{ "Register with DNS load-balancing", register_dns_load_balancing }
{ "Register with DNS load-balancing", register_dns_load_balancing },
{ "Nonce reutilization", reuse_nonce }
};
test_suite_t register_test_suite = {
......@@ -592,3 +714,4 @@ test_suite_t register_test_suite = {
register_tests
};
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