Commit 3e18e32b authored by Pekka Pessi's avatar Pekka Pessi

Testing authenticating REGISTER.

Authenticating nua_register(), and nua_authenticate() to nua_unregister().

darcs-hash:20060109165800-65a35-1959a2a2f31dcfdf0d67f57405daef3ca7c28115.gz
parent 2dd80e65
......@@ -1668,19 +1668,28 @@ int nh_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
return retval;
}
/** Collect challenges from response */
/** Collect challenges from response.
*
* @return Number of updated challenges, 0 if no updates found.
* @retval -1 upon error.
*/
static
int nh_challenge(nua_handle_t *nh, sip_t const *sip)
{
int server = 0, proxy = 0;
if (sip->sip_www_authenticate)
auc_challenge(&nh->nh_auth, nh->nh_home, sip->sip_www_authenticate,
sip_authorization_class);
server = auc_challenge(&nh->nh_auth, nh->nh_home, sip->sip_www_authenticate,
sip_authorization_class);
if (sip->sip_proxy_authenticate)
auc_challenge(&nh->nh_auth, nh->nh_home, sip->sip_proxy_authenticate,
sip_proxy_authorization_class);
proxy = auc_challenge(&nh->nh_auth, nh->nh_home, sip->sip_proxy_authenticate,
sip_proxy_authorization_class);
return 0;
if (server < 0 || proxy < 0)
return -1;
return server + proxy;
}
/** Create request message.
......@@ -3108,12 +3117,11 @@ int crequest_check_restart(nua_handle_t *nh,
}
else if (method != sip_method_ack && method != sip_method_cancel &&
((status == 401 && sip->sip_www_authenticate) ||
(status == 407 && sip->sip_proxy_authenticate))) {
(status == 407 && sip->sip_proxy_authenticate)) &&
nh_challenge(nh, sip) > 0) {
sip_t *rsip;
int done;
nh_challenge(nh, sip);
rsip = sip_object(cr->cr_msg);
/* XXX - check for instant restart */
......@@ -3320,7 +3328,27 @@ register_expires_contacts(msg_t *msg, sip_t *sip)
static void
restart_register(nua_handle_t *nh, tagi_t *tags)
{
crequest_restart(nh, nh->nh_cr, process_response_to_register, tags);
struct nua_client_request *cr = nh->nh_cr;
msg_t *msg;
cr->cr_restart = NULL;
if (!cr->cr_msg)
return;
msg = crequest_message(nh->nh_nua, nh, cr, 1,
SIP_METHOD_UNKNOWN,
TAG_NEXT(tags));
if (msg && cr->cr_usage && cr->cr_usage->du_terminating)
register_expires_contacts(msg, sip_object(msg));
cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta,
process_response_to_register, nh, NULL, msg,
SIPTAG_END(), TAG_NEXT(tags));
if (!cr->cr_orq)
msg_destroy(msg);
}
static
......
......@@ -797,6 +797,7 @@ extern tag_typedef_t nutag_sip_parser_ref;
* @par Values
* NULL terminated string of format: \n
* basic digest scheme:"realm":user:password \n
* @b NOTE the double quotes around realm!
* For example: \n
* \code Digest:"nokia proxy":xyz:secret \endcode
*
......
......@@ -50,6 +50,7 @@ struct call;
#include <su_tag_io.h>
#include <test_proxy.h>
#include <auth_module.h>
#include <stddef.h>
#include <stdlib.h>
......@@ -1088,6 +1089,19 @@ int test_params(struct context *ctx)
/* ======================================================================== */
static char passwd_name[] = "tmp_sippasswd.XXXXXX";
static void rmtmp(void)
{
if (passwd_name[0])
unlink(passwd_name);
}
static char const passwd[] =
"alice:secret:\n"
"bob:secret:\n"
"charlie:secret:\n";
int test_init(struct context *ctx, int start_proxy, url_t const *o_proxy)
{
BEGIN();
......@@ -1102,10 +1116,26 @@ int test_init(struct context *ctx, int start_proxy, url_t const *o_proxy)
su_root_threading(ctx->root, ctx->threading);
if (start_proxy && !o_proxy) {
int temp;
if (print_headings)
printf("TEST NUA-2.0.0: init proxy P\n");
ctx->p = test_proxy_create(ctx->root);
temp = mkstemp(passwd_name); TEST_1(temp != -1);
atexit(rmtmp); /* Make sure temp file is unlinked */
TEST(write(temp, passwd, strlen(passwd)), strlen(passwd));
TEST_1(close(temp) == 0);
ctx->p = test_proxy_create(ctx->root,
AUTHTAG_METHOD("Digest"),
AUTHTAG_REALM("test-proxy"),
AUTHTAG_OPAQUE("kuik"),
AUTHTAG_DB(passwd_name),
AUTHTAG_QOP("auth-int"),
AUTHTAG_ALGORITHM("md5-sess"),
TAG_END());
if (print_headings)
printf("TEST NUA-2.0.0: PASSED\n");
......@@ -1204,6 +1234,8 @@ int test_register(struct context *ctx)
struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
struct call *a_call = a->reg, *b_call = b->reg, *c_call = c->reg;
struct event *e;
sip_t const *sip;
/* REGISTER test
......@@ -1219,8 +1251,28 @@ int test_register(struct context *ctx)
TEST_1(a_call->nh = nua_handle(a->nua, a_call, TAG_END()));
do_register(a, a_call, a_call->nh, SIPTAG_TO(a->to), TAG_END());
run_a_until(ctx, -1, save_until_final_response);
run_a_until(ctx, -1, until_final_response);
TEST_1(e = a->call->events.head);
TEST_E(e->data->e_event, nua_r_register);
TEST_1(sip = sip_object(e->data->e_msg));
TEST(e->data->e_status, 401);
TEST(sip->sip_status->st_status, 401);
TEST_1(!sip->sip_contact);
TEST_1(!e->next);
free_events_in_list(ctx, a->call);
authenticate(a, a_call, a_call->nh,
NUTAG_AUTH("Digest:\"test-proxy\":alice:secret"), TAG_END());
run_a_until(ctx, -1, save_until_final_response);
TEST_1(e = a->call->events.head);
TEST_E(e->data->e_event, nua_r_register);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_contact);
TEST_1(!e->next);
free_events_in_list(ctx, a->call);
if (print_headings)
printf("TEST NUA-2.1: PASSED\n");
......@@ -1231,8 +1283,28 @@ int test_register(struct context *ctx)
TEST_1(b_call->nh = nua_handle(b->nua, b_call, TAG_END()));
do_register(b, b_call, b_call->nh, SIPTAG_TO(b->to), TAG_END());
run_b_until(ctx, -1, save_until_final_response);
run_b_until(ctx, -1, until_final_response);
TEST_1(e = b->call->events.head);
TEST_E(e->data->e_event, nua_r_register);
TEST_1(sip = sip_object(e->data->e_msg));
TEST(e->data->e_status, 401);
TEST(sip->sip_status->st_status, 401);
TEST_1(!sip->sip_contact);
TEST_1(!e->next);
free_events_in_list(ctx, b->call);
authenticate(b, b_call, b_call->nh,
NUTAG_AUTH("Digest:\"test-proxy\":bob:secret"), TAG_END());
run_b_until(ctx, -1, save_until_final_response);
TEST_1(e = b->call->events.head);
TEST_E(e->data->e_event, nua_r_register);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_contact);
TEST_1(!e->next);
free_events_in_list(ctx, b->call);
if (print_headings)
printf("TEST NUA-2.2: PASSED\n");
......@@ -1243,8 +1315,28 @@ int test_register(struct context *ctx)
TEST_1(c_call->nh = nua_handle(c->nua, c_call, TAG_END()));
do_register(c, c_call, c_call->nh, SIPTAG_TO(c->to), TAG_END());
run_c_until(ctx, -1, save_until_final_response);
TEST_1(e = c->call->events.head);
TEST_E(e->data->e_event, nua_r_register);
TEST_1(sip = sip_object(e->data->e_msg));
TEST(e->data->e_status, 401);
TEST(sip->sip_status->st_status, 401);
TEST_1(!sip->sip_contact);
TEST_1(!e->next);
free_events_in_list(ctx, c->call);
run_c_until(ctx, -1, until_final_response);
authenticate(c, c_call, c_call->nh,
NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"), TAG_END());
run_c_until(ctx, -1, save_until_final_response);
TEST_1(e = c->call->events.head);
TEST_E(e->data->e_event, nua_r_register);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_contact);
TEST_1(!e->next);
free_events_in_list(ctx, c->call);
if (print_headings)
printf("TEST NUA-2.3: PASSED\n");
......@@ -1311,6 +1403,32 @@ int test_unregister(struct context *ctx)
if (print_headings)
printf("TEST NUA-13.3: un-REGISTER c\n");
/* Unregister using another handle */
TEST_1(c->call->nh = nua_handle(c->nua, c->call, TAG_END()));
unregister(c, c->call, c->call->nh, SIPTAG_TO(c->to), TAG_END());
run_c_until(ctx, -1, save_until_final_response);
TEST_1(e = c->call->events.head);
TEST_E(e->data->e_event, nua_r_unregister);
TEST_1(sip = sip_object(e->data->e_msg));
TEST(e->data->e_status, 401);
TEST(sip->sip_status->st_status, 401);
TEST_1(!sip->sip_contact);
TEST_1(!e->next);
free_events_in_list(ctx, c->call);
authenticate(c, c->call, c->call->nh,
NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"), TAG_END());
run_c_until(ctx, -1, save_until_final_response);
TEST_1(e = c->call->events.head);
TEST_E(e->data->e_event, nua_r_unregister);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(!sip->sip_contact);
TEST_1(!e->next);
free_events_in_list(ctx, c->call);
if (c->reg->nh) {
unregister(c, NULL, c->reg->nh, TAG_END());
run_c_until(ctx, -1, save_until_final_response);
......@@ -2245,6 +2363,111 @@ int test_reject_401(struct context *ctx)
END();
}
/* ------------------------------------------------------------------------ */
/* Reject call with 401 and bad challenge */
/*
A reject-401-aka B
| |
|-------INVITE------>|
|<----100 Trying-----|
|<--------401--------|
|---------ACK------->|
*/
CONDITION_FUNCTION(reject_401_aka)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
respond(ep, call, nh, SIP_401_UNAUTHORIZED,
/* Send a challenge that we do not grok */
SIPTAG_WWW_AUTHENTICATE_STR("Digest realm=\"test_nua\", "
"nonce=\"nsdhfuds\", algorithm=SHA0-AKAv6, "
"qop=\"auth\""),
TAG_END());
return 0;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
}
int test_reject_401_aka(struct context *ctx)
{
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event const *e;
sip_t const *sip;
if (print_headings)
printf("TEST NUA-4.6: invalid challenge \n");
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
invite(a, a_call, a_call->nh,
TAG_IF(!ctx->p, NUTAG_URL(b->contact->m_url)),
SIPTAG_SUBJECT_STR("reject-401-aka"),
SOATAG_USER_SDP_STR(a_call->sdp),
TAG_END());
run_ab_until(ctx, -1, save_until_final_response, -1, reject_401_aka);
/*
Client transitions
INIT -(C1)-> CALLING -(C6a)-> TERMINATED/INIT
*/
TEST_1(e = a_call->events.head); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
TEST_1(is_offer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(sip_object(e->data->e_msg)->sip_status->st_status, 401);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, a_call);
/*
Server transitions:
INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED
*/
TEST_1(e = b_call->events.head); TEST_E(e->data->e_event, nua_i_invite);
TEST_1(sip = sip_object(e->data->e_msg));
TEST(e->data->e_status, 100);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
TEST_1(is_offer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, b_call);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-4.6: PASSED\n");
END();
}
/* ---------------------------------------------------------------------- */
int test_mime_negotiation(struct context *ctx)
{
BEGIN();
......@@ -4857,6 +5080,7 @@ int main(int argc, char *argv[])
retval |= test_reject_302(ctx); SINGLE_FAILURE_CHECK();
retval |= test_reject_401(ctx); SINGLE_FAILURE_CHECK();
retval |= test_mime_negotiation(ctx); SINGLE_FAILURE_CHECK();
retval |= test_reject_401_aka(ctx); SINGLE_FAILURE_CHECK();
retval |= test_call_cancel(ctx); SINGLE_FAILURE_CHECK();
retval |= test_early_bye(ctx); SINGLE_FAILURE_CHECK();
retval |= test_call_hold(ctx); SINGLE_FAILURE_CHECK();
......
......@@ -48,6 +48,12 @@ struct registration_entry;
#include <sip_header.h>
#include <sip_status.h>
#include <sip_util.h>
#include <auth_module.h>
#include <su_tagarg.h>
#include <msg_addr.h>
#include <stdlib.h>
#include <assert.h>
#define LIST_PROTOS(STORAGE, PREFIX, T) \
STORAGE void PREFIX ##_insert(T **list, T *node), \
......@@ -78,7 +84,11 @@ extern int LIST_DUMMY_VARIABLE
struct proxy {
su_home_t home[1];
su_clone_r clone;
tagi_t *tags;
su_root_t *root;
auth_mod_t *auth;
nta_agent_t *agent;
url_t const *uri;
......@@ -144,12 +154,14 @@ test_proxy_init(su_root_t *root, struct proxy *proxy)
proxy->root = root;
proxy->auth = auth_mod_create(root, TAG_NEXT(proxy->tags));
proxy->agent = nta_agent_create(root,
URL_STRING_MAKE("sip:0.0.0.0:*"),
NULL, NULL,
NTATAG_UA(0),
TAG_END());
proxy->defleg = nta_leg_tcreate(proxy->agent,
proxy_request,
proxy,
......@@ -159,7 +171,7 @@ test_proxy_init(su_root_t *root, struct proxy *proxy)
if (!proxy->defleg)
return -1;
t = su_zalloc(proxy->home, sizeof *t);
t = su_zalloc(proxy->home, sizeof *t);
if (!t)
return -1;
......@@ -188,14 +200,23 @@ test_proxy_deinit(su_root_t *root, struct proxy *proxy)
}
nta_agent_destroy(proxy->agent);
free(proxy->tags);
}
/* Create tst proxy object */
struct proxy *test_proxy_create(su_root_t *root)
struct proxy *test_proxy_create(su_root_t *root,
tag_type_t tag, tag_value_t value, ...)
{
struct proxy *p = su_home_new(sizeof *p);
if (p) {
ta_list ta;
ta_start(ta, tag, value);
p->tags = tl_llist(ta_tags(ta));
ta_end(ta);
if (su_clone_start(root,
p->clone,
p,
......@@ -368,14 +389,51 @@ LIST_BODIES(static, proxy_transaction, struct proxy_transaction, next, prev);
static int check_unregister(sip_t const *sip);
auth_challenger_t const registrar_challenger[1] =
{{
SIP_401_UNAUTHORIZED,
sip_www_authenticate_class,
sip_authentication_info_class
}};
int process_register(struct proxy *proxy,
nta_incoming_t *irq,
sip_t const *sip)
{
auth_status_t *as;
msg_t *msg;
struct registration_entry *e;
sip_contact_t *old_binding, *new_binding;
int unregister;
msg = nta_incoming_getrequest(irq);
as = su_home_clone(proxy->home, (sizeof *as));
as->as_status = 500, as->as_phrase = sip_500_Internal_server_error;
as->as_method = sip->sip_request->rq_method_name;
as->as_source = msg_addrinfo(msg);
as->as_user_uri = sip->sip_from->a_url;
as->as_display = sip->sip_from->a_display;
if (sip->sip_payload)
as->as_body = sip->sip_payload->pl_data,
as->as_bodylen = sip->sip_payload->pl_len;
auth_mod_check_client(proxy->auth, as, sip->sip_authorization,
registrar_challenger);
if (as->as_status != 0) {
assert(as->as_status >= 300);
nta_incoming_treply(irq,
as->as_status, as->as_phrase,
SIPTAG_HEADER((void *)as->as_info),
SIPTAG_HEADER((void *)as->as_response),
TAG_END());
return as->as_status;
}
unregister = check_unregister(sip);
e = registration_entry_find(proxy, sip->sip_to->a_url);
......
......@@ -32,7 +32,8 @@ SOFIA_BEGIN_DECLS
struct proxy;
struct proxy *test_proxy_create(su_root_t *);
struct proxy *test_proxy_create(su_root_t *, tag_type_t, tag_value_t, ...);
void test_proxy_destroy(struct proxy *);
url_t const *test_proxy_uri(struct proxy const *);
......
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