[OpenSIPS-Users] DIGEST AUTH with no uac_auth function(CSeq trouble workaround)
neumann
itsroot at gmail.com
Thu Jan 22 16:29:32 CET 2015
If someone interesting this is set of routes to make Digest authorization manually(with no uac_auth)
I would be grateful if somebody optimizes this workaround or find security troubles.
route[dispatch_out] {
#For testing, I used the dispatcher module
#You can create your own search method register data for proxy in this cfg is «hardcoded» val $avp(registrant)=6
#Now I use gateway attributes in dr_gateways table
#Username and password and aor I get from registrant table
$avp(registrant)=6;
#dispatcher set 1001 is set contain proxy which need to auth
#lets go!
if(!ds_select_domain("1001","8")){
send_reply("404", "No destination");
exit;
}
#clearing auth flag
resetflag(7);
#get auth data from registrant table
avp_db_query("select username, password, aor from registrant where id=$avp(registrant)","$avp(stored_username);$avp(stored_password);$avp(stored_aor)");
#build new From-hdr with registrant data
uac_replace_from("$avp(stored_username)", "$avp(stored_aor)");
#build new To-hdr with registrant data
$avp(stored_to)="sip:" + $(ru{uri.user}) + "@" + $(avp(stored_to){uri.host}) + ":" + $(ru{uri.port});
uac_replace_to("$avp(stored_to)");
t_on_failure("rtf_dispatch_out");
t_on_reply("auth_reply");
t_relay();
exit;
}
onreply_route[auth_reply] {
if ( t_check_status("401|407") ) {
#if is not first "unauthorized" - do nothing (see below)
if (isflagset(7)) {
return;
}
#special route to parce WWW-Atuh hdr
route(parse_digest);
} else if ( t_check_status("200") ) {
#special route to decrease cseq(see below)
route(dec_cseq);
}
}
route[parse_digest]{
#saving Auth HDR of 401/407 reply
$avp(stored_digest)=$hdr(WWW-Authenticate);
xlog("L_INFO", "Route PARSE_DIGEST orig WWW-Authenticate header is $hdr(WWW-Authenticate);");
#some transformations for parse
avp_subst("$avp(stored_digest)", "/, /;/g");
avp_subst("$avp(stored_digest)", "/Digest //g");
avp_subst("$avp(stored_digest)", "/\"//g");
xlog("L_INFO", "Route PARSE_DIGEST digest params is $avp(stored_digest)");
#use script transformations to get values of HDR and save it in AVPs
$avp(stored_realm)=$(avp(stored_digest){param.value,realm});
$avp(stored_nonce)=$(avp(stored_digest){param.value,nonce});
if $(avp(stored_digest){param.exist,algorithm}) {
$avp(stored_algorithm)=$(avp(stored_digest){param.value,algorithm});
} else {
$avp(stored_algorithm)="MD5";
}
if $(avp(stored_digest){param.exist,qop}) {
$avp(stored_qop)=$(avp(stored_digest){param.value,qop});
} else {
$avp(stored_qop)="none";
}
xlog("L_INFO", "Route PARSE_DIGEST digest algorithm is $avp(stored_algorithm)");
xlog("L_INFO", "Route PARSE_DIGEST digest realm is $avp(stored_realm)");
xlog("L_INFO", "Route PARSE_DIGEST digest nonce is $avp(stored_nonce)");
xlog("L_INFO", "Route PARSE_DIGEST digest qop is $avp(stored_qop)");
return;
}
#failure route - processing 401/407 error and send new invite with Authorization HDR
failure_route[rtf_dispatch_out]{
xlog("L_INFO", "DISPATCHER OUTBOUND FILED");
if ( t_check_status("401|407") ) {
if (isflagset(7)) {
#If its not first «unauthorized» - registration data is wrong
t_reply("503","Authentication failed");
exit;
}
#go to route wich append auth HDR
route(append_authorize);
#route which increase cseq
route(inc_cseq);
t_on_failure("rtf_dispatch_out");
t_relay();
exit;
}
if (t_was_cancelled()) {
exit;
}
#this is standard part of dispatcher failure route
xlog("L_INFO", "IAM IN FAILURE ROUTE DISPATCH\n");
ds_mark_dst("p");
xlog("L_INFO", "IAM SELECT NEW DESTINATION\n");
if (ds_next_domain()) {
$avp(final_reply_timeout) = 2;
t_on_failure("rtf_dispatch_out");
t_relay();
exit;
}
}
#this route to append Authorization HDR to second invite
route[append_authorize] {
xlog("L_INFO", "Route APPEND_AUTHORIZE orig ruri is $ru");
#saving ruri for use it for build response
$avp(stored_ruri)="sip:" + $(ru{uri.user}) + "@" + $(ru{uri.host});
xlog("L_INFO", "Route APPEND_AUTHORIZE parsed ruri is $avp(stored_ruri)");
#calculate ha1
$avp(ha1)=$avp(stored_username) + ":" + $avp(stored_realm) + ":" + $avp(stored_password);
xlog("L_INFO", "Route APPEND_AUTHORIZE ha1 is $avp(ha1)");
$avp(ha1)=$(avp(ha1){s.md5});
xlog("L_INFO", "Route APPEND_AUTHORIZE ha1 is $avp(ha1)");
#switch for different types of qop
switch($avp(stored_qop))
{
case "none":
$avp(ha2)=$rm + ":" + $avp(stored_ruri);
xlog("L_INFO", "Route APPEND_AUTHORIZE $rm ha2 is $avp(ha2)");
$avp(ha2)=$(avp(ha2){s.md5});
xlog("L_INFO", "Route APPEND_AUTHORIZE $rm ha2 is $avp(ha2)");
$avp(auth_response)=$avp(ha1) + ":" + $avp(stored_nonce) + ":" + $avp(ha2);
xlog("L_INFO", "Route APPEND_AUTHORIZE auth_response is $avp(auth_response)");
$avp(auth_response)=$(avp(auth_response){s.md5});
xlog("L_INFO", "Route APPEND_AUTHORIZE auth_response is $avp(auth_response)");
$avp(auth_hdr)="Authorization: Digest username=\"" +
$avp(stored_username) +
"\", realm=\"" +
$avp(stored_realm) +
"\", nonce=\"" +
$avp(stored_nonce) +
"\", uri=\"" +
$avp(stored_ruri) +
"\", response=\"" +
$avp(auth_response) +
"\", algorithm=" +
$avp(stored_algorithm) +
"\r\n";
break;
case "auth":
$avp(ha2)=$rm + ":" + $avp(stored_ruri);
xlog("L_INFO", "Route APPEND_AUTHORIZE $rm ha2 is $avp(ha2)");
$avp(ha2)=$(avp(ha2){s.md5});
xlog("L_INFO", "Route APPEND_AUTHORIZE $rm ha2 is $avp(ha2)");
$avp(stored_cnonce)=$(RANDOM{s.dec2hex});
#xlog("random testing $(RANDOM{s.dec2hex})\n");
$avp(nc)="00000001";
$avp(auth_response)=$avp(ha1) + ":" + $avp(stored_nonce) + ":00000001:" + $avp(stored_cnonce) + ":auth:" + $avp(ha2);
xlog("L_INFO", "Route APPEND_AUTHORIZE auth_response is $avp(auth_response)");
$avp(auth_response)=$(avp(auth_response){s.md5});
xlog("L_INFO", "Route APPEND_AUTHORIZE auth_response is $avp(auth_response)");
$avp(auth_hdr)="Authorization: Digest username=\"" +
$avp(stored_username) +
"\", realm=\"" +
$avp(stored_realm) +
"\", nonce=\"" +
$avp(stored_nonce) +
"\", uri=\"" +
$avp(stored_ruri) +
"\", response=\"" +
$avp(auth_response) +
"\", algorithm=" +
$avp(stored_algorithm) +
"\", qop=auth" +
", cnonce=\"" +
$avp(stored_cnonce) +
"\", nc=00000001" +
"\r\n";
break;
case "auth-int":
#TODO
xlog("L_INFO", "Route APPEND_AUTHORIZE not supported qop auth-int");
break;
default:
xlog("L_INFO", "Route APPEND_AUTHORIZE unexpected qop is $avp(stored_qop)");
}
xlog("L_INFO", "Route APPEND_AUTHORIZE auth_hdr is <$avp(auth_hdr)>");
#Append HDR to Invite
if (append_hf("$avp(auth_hdr)")) {
setflag(7);
}
return;
}
#two short routes to inc or dec cseq value
#it use dialog module!!!!!!
#I need dlg_flag for check manual cseq updating
---------------------------------------------------------
…...
route[inc_cseq]{
if(remove_hf("CSeq")){
$var(cseq) = $(cs{s.int}) + 1;
$var(cseq) = "CSeq: " + $var(cseq) + " " + $rm + "\r\n";
append_hf("$var(cseq)");
if (!is_dlg_flag_set("7")) {
set_dlg_flag("7");
}
xlog("L_INFO", "INCREASE CSEQ NEW IS <$var(cseq)>");
}
return;
}
route[dec_cseq]{
if(remove_hf("CSeq")){
$var(cseq) = $(cs{s.int}) - 1;
$var(cseq) = "CSeq: " + $var(cseq) + " " + $rm + "\r\n";
append_hf("$var(cseq)");
if (!is_dlg_flag_set("7")) {
set_dlg_flag("7");
}
xlog("L_INFO", "DECREASE CSEQ NEW IS<$var(cseq)>");
}
return;
}
#and in standard part of route logic
#that looks like this:
if (has_totag()) {
if (loose_route() || match_dialog() ) {
if (is_method("BYE")) {
setflag(ACC_DO); # do accounting ...
setflag(ACC_FAILED); # ... even if the transaction fails
} else if (is_method("INVITE")) {
record_route();
} else if (is_method("ACK")) {
#Decreasing cseq back
if (is_dlg_flag_set("7")) {
route(inc_cseq);
}
}
…………..
}
…...
---------------------------------------------------------
Thanks!
————————————
Timofeev Dmitry
VoIP Engineer
Linux, Asterisk, Freeswitch, Cisco solutions
Skype: itsroot
icq: 227227933
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.opensips.org/pipermail/users/attachments/20150122/fa1442d5/attachment-0001.htm>
More information about the Users
mailing list