From 082ecbfc40b5d43a5330f0424089366521424b2a Mon Sep 17 00:00:00 2001 From: lazedo Date: Thu, 7 May 2020 17:26:43 +0000 Subject: [PATCH] start to support authentication for other methods --- kamailio/auth.cfg | 172 ----------------------- kamailio/authorization-role.cfg | 23 --- kamailio/authorization.cfg | 242 ++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+), 195 deletions(-) delete mode 100644 kamailio/auth.cfg delete mode 100644 kamailio/authorization-role.cfg create mode 100644 kamailio/authorization.cfg diff --git a/kamailio/auth.cfg b/kamailio/auth.cfg deleted file mode 100644 index 463729b..0000000 --- a/kamailio/auth.cfg +++ /dev/null @@ -1,172 +0,0 @@ -#!trydef KZ_STRICT_AUTH 1 -kazoo.strict_auth = KZ_STRICT_AUTH descr "only allow requests from registered or trusted sources" - -route[AUTH] -{ - if (isflagset(FLAG_INTERNALLY_SOURCED)) { - $avp(auth_allowed) = "true"; - return; - } - - if (!is_method("INVITE|MESSAGE|REFER")) { - $avp(auth_allowed) = "true"; - return; - } - - #!ifdef DISPATCHER_ROLE - route(SETUP_AUTH_HEADERS); - #!endif -} - -route[AUTH_HEADERS] -{ - remove_hf_re("^X-"); - - if (!is_method("INVITE|MESSAGE|REFER")) { - return; - } - - xavp_params_implode("hf", "$var(outx)"); - $var(out) = $(var(outx){re.subst,/^(.*);$$/\1/}); - $var(c) = $(var(out){param.count}); - xlog("L_DEBUG", "$ci|auth|headers $var(c) => $var(out) => $var(outx)\n"); - while($var(c) > 0) { - $var(idx) = $var(c) - 1; - xlog("L_DEBUG", "$ci|auth|adding $(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\n"); - append_hf("$(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\r\n"); - $var(c) = $var(c) - 1; - } - -} - -route[AUTH_HEADERS_JSON] -{ - xavp_params_implode("hf", "$var(outx)"); - $var(out) = $(var(outx){re.subst,/^(.*);$$/\1/}); - $var(c) = $(var(out){param.count}); - $var(headers_json) = ""; - $var(sep) = ""; - xlog("L_DEBUG", "$ci|auth|headers $var(c) => $var(out) => $var(outx)\n"); - while($var(c) > 0) { - $var(idx) = $var(c) - 1; - xlog("L_DEBUG", "$ci|auth|adding $(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\n"); - append_hf("$(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\r\n"); - $var(headers_json) = $_s($var(headers_json)$var(sep)"$(var(out){param.name,$var(idx)})" : "$(var(out){param.valueat,$var(idx)}{s.unescape.param})"); - $var(c) = $var(c) - 1; - $var(sep) = " , "; - } - $var(headers_json) = $_s({ $var(headers_json) }); -} - -route[SETUP_AUTH_HEADERS] -{ - - $avp(auth_allowed) = "false"; - $xavp(hf=>X-AUTH-IP) = $si; - $xavp(hf[0]=>X-AUTH-PORT) = $sp; - - #!ifdef REGISTRAR_ROLE - $avp(is_registered) = "false"; - $xavp(regcfg=>match_received) = $su; - if (registered("location","sip:$Au", 2, 1) == 1) { - $avp(is_registered) = "true"; - $avp(auth_allowed) = "true"; - route(AUTH_XAVP_TOKEN); - return; - } else if(is_present_hf("Proxy-Authorization")) { - if(registered("location", "sip:$au@$ar", 2, 1) == 1) { - xlog("L_INFO", "$ci|auth|from sip:$au@$ar\n"); - $avp(is_registered) = "true"; - $avp(auth_allowed) = "true"; - route(AUTH_XAVP_TOKEN); - return; - } - } - #!endif - - if (allow_source_address()) { - $avp(auth_allowed) = "true"; - $xavp(hf[0]=>X-AUTH-Token) = $avp(trusted_x_header); - $xavp(hf[0]=>X-AUTH-URI-User) = $rU; - $xavp(hf[0]=>X-AUTH-URI-Realm) = $rd; - if(is_present_hf("P-Asserted-Identity") && $(ai{uri.user}) != "") { - $xavp(hf[0]=>X-AUTH-From-User) = $(ai{uri.user}); - } else if(is_present_hf("P-Preferred-Identity") && $pU != "") { - $xavp(hf[0]=>X-AUTH-From-User) = $pU; - } else if(is_present_hf("Remote-Party-ID") && $(re{uri.user}) != "") { - $xavp(hf[0]=>X-AUTH-From-User) = $(re{uri.user}); - } else { - $xavp(hf[0]=>X-AUTH-From-User) = $fU; - } - if($xavp(hf=>X-AUTH-From-User) =~ "^\+?00+$") { - $xavp(hf[0]=>X-AUTH-From-Is-Anonymous) = "true"; - $xavp(hf[0]=>X-AUTH-From-User) = $null; - } else if($(xavp(hf=>X-AUTH-From-User){s.tolower}) =~ "^anonymous$") { - $xavp(hf[0]=>X-AUTH-From-Is-Anonymous) = "true"; - $xavp(hf[0]=>X-AUTH-From-User) = $null; - } - return; - } - -} - -#!ifdef REGISTRAR_ROLE - -route[AUTH_XAVP_TOKEN] -{ - #!ifdef WITH_AUTH_TOKEN - route(AUTH_TOKEN); - #!else - route(AUTH_CCVS) - #!endif -} - -route[AUTH_TOKEN] -{ - if($(xavp(ulattrs=>token){s.len}) > 0) { - $xavp(hf[0]=>X-AUTH-Token) = $xavp(ulattrs=>token); - } else { - if($(xavp(ulattrs=>Authorizing-ID){s.len}) > 0 && $(xavp(ulattrs=>Account-ID){s.len})) { - $xavp(hf[0]=>X-AUTH-Token) = $_s($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID})@$(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID})); - } - } -} - -route[AUTH_CCVS] -{ - if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}{s.len}) > 0 && $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}{s.len}) > 0) - $xavp(hf[0]=>X-AUTH-Token) = $_s($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID})@$(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID})); - - if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}{s.len}) > 0) - $xavp(hf[0]=>X-ecallmgr_Account-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}); - - if($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}{s.len}) > 0) - $xavp(hf[0]=>X-ecallmgr_Authorizing-Type) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}); - - if($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID}{s.len}) > 0) - $xavp(hf[0]=>X-ecallmgr_Authorizing-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID}); - - if($(xavp(ulattrs=>custom_channel_vars){kz.json,Username}{s.len}) > 0) - $xavp(hf[0]=>X-ecallmgr_Username) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Username}); - - if($(xavp(ulattrs=>custom_channel_vars){kz.json,Realm}{s.len}) > 0) - $xavp(hf[0]=>X-ecallmgr_Realm) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Realm}); - - if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Realm}{s.len}) > 0) - $xavp(hf[0]=>X-ecallmgr_Account-Realm) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Realm}); - - if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Name}{s.len}) > 0) - $xavp(hf[0]=>X-ecallmgr_Account-Name) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Name}{s.escape.param}); - - if($(xavp(ulattrs=>custom_channel_vars){kz.json,Presence-ID}{s.len}) > 0) - $xavp(hf[0]=>X-ecallmgr_Presence-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Presence-ID}); - - if($(xavp(ulattrs=>custom_channel_vars){kz.json,Owner-ID}{s.len}) > 0) - $xavp(hf[0]=>X-ecallmgr_Owner-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Owner-ID}); - - if($(xavp(ulattrs=>custom_channel_vars){kz.json,Hotdesk-Current-ID}{s.len}) > 0) - $xavp(hf[0]=>X-ecallmgr_Hotdesk-Current-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Hotdesk-Current-ID}); - -} - -#!endif diff --git a/kamailio/authorization-role.cfg b/kamailio/authorization-role.cfg deleted file mode 100644 index 5b55be2..0000000 --- a/kamailio/authorization-role.cfg +++ /dev/null @@ -1,23 +0,0 @@ -## to be enhanced - -route[AUTHORIZATION_CHECK] -{ - if (!is_method("MESSAGE|NOTIFY|SUBSCRIBE|PUBLISH")) - return; - - if(has_totag()) - return; - - if (isflagset(FLAG_INTERNALLY_SOURCED)) - return; - - if (isflagset(FLAG_TRUSTED_SOURCE)) - return; - - $xavp(regcfg=>match_received) = $su; - if(!(registered("location", "$fu", 2, 1) == 1 && $(xavp(ulattrs=>custom_channel_vars){s.len}) > 1)) { - xlog("L_INFO", "$ci|log|not authorized $fu from $si:$sp\n"); - send_reply("503", "Not Registered"); - exit; - } -} diff --git a/kamailio/authorization.cfg b/kamailio/authorization.cfg new file mode 100644 index 0000000..579fab4 --- /dev/null +++ b/kamailio/authorization.cfg @@ -0,0 +1,242 @@ + +modparam("statistics","variable", "auth:amqp_not_available") +modparam("statistics","variable", "auth:new_tran") +modparam("statistics","variable", "auth:challenge") +modparam("statistics","variable", "auth:amqp_async_error") +modparam("statistics","variable", "auth:amqp_returned") +modparam("statistics","variable", "auth:amqp_timeout") +modparam("statistics","variable", "auth:authn_perm_err") +modparam("statistics","variable", "auth:authn_err") +modparam("statistics","variable", "auth:authn_resp") +modparam("statistics","variable", "auth:authn_unknown") + + +route[AUTHORIZATION] +{ + if (isflagset(FLAG_INTERNALLY_SOURCED)) { + return; + } + + if (isflagset(FLAG_AUTHORIZED)) { + return; + } + + if (!is_method("INVITE|REFER|MESSAGE|NOTIFY|SUBSCRIBE|PUBLISH")) { + setflag(FLAG_AUTHORIZED); + return; + } + + route(AUTHORIZATION_CHECK); + + if (!isflagset(FLAG_AUTHORIZED)) { + xlog("L_INFO", "$ci|auth|challenging $rm from $Au $si:$sp\n"); + $var(auth) = auth_challenge("$fd", "4"); + update_stat("auth:challenge", "+1"); + if($var(auth) != 1) { + xlog("L_ERROR", "$ci|register|error creating or sending challenge to $rm attempt for $fu from $si:$sp\n"); + send_reply("403", "Forbidden"); + } + exit; + } + +} + +route[AUTHORIZATION_CHECK] +{ + + route(AUTHORIZATION_CHECK_TRUSTED); + route(AUTHORIZATION_CHECK_REGISTERED); + +} + +route[AUTHORIZATION_CHECK_TRUSTED] +{ + if (isflagset(FLAG_AUTHORIZED)) return; + + if (isflagset(FLAG_TRUSTED_SOURCE)) { + route(SETUP_AUTH_ORIGIN); + route(SETUP_AUTH_TRUSTED); + setflag(FLAG_AUTHORIZED); + } +} + +route[AUTHORIZATION_CHECK_REGISTERED] +{ + if (isflagset(FLAG_AUTHORIZED)) return; + + #!ifdef REGISTRAR_ROLE + $xavp(regcfg=>match_received) = $su; + if (registered("location","sip:$Au", 2, 1) == 1) { + route(SETUP_AUTH_ORIGIN); + $xavp(hf[0]=>X-AUTH-Token) = $xavp(ulattrs=>token); + setflag(FLAG_AUTHORIZED); + } + #!endif +} + + + +route[HANDLE_AUTHORIZATION] +{ + + if(!is_present_hf("Proxy-Authorization")) { + route(MAIN); + exit; + } + + $var(amqp_payload_request) = $_s({"Event-Category" : "directory" , "Event-Name" : "authn_req", "Method" : "REGISTER", "Auth-Nonce" : "$adn", "Auth-Realm" : "$fd", "Auth-User" : "$fU", "From" : "$fu", "To" : "$tu", "Orig-IP" : "$si", "Orig-Port" : "$sp", "User-Agent" : "$(ua{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Contact" : "$(ct{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Call-ID" : "$ci" }); + $var(amqp_routing_key) = $_s($def(REGISTRAR_AMQP_RK_PREFIX)$(fd{kz.encode})); + $avp(kz_timeout) = $sel(cfg_get.kazoo.registrar_query_timeout_ms); + $xavp(deltas=>query) = $(TV(Sn){s.replace,.,}); + + xlog("L_DEBUG", "$ci|amqp|publishing to $def(REGISTRAR_AMQP_EXCHANGE) => $var(amqp_routing_key) : $def(REGISTRAR_AMQP_FLAGS) : $var(amqp_payload_request)\n"); + if(kazoo_async_query("$def(REGISTRAR_AMQP_EXCHANGE)", $var(amqp_routing_key), $var(amqp_payload_request), "KZ_AUTHORIZATION_CHECK_REPLY", "KZ_AUTHORIZATION_CHECK_TIMEOUT", "$def(REGISTRAR_AMQP_FLAGS)") != 1) { + xlog("L_INFO", "$ci|log|failed to send registrar query for authentication credentials for $Au $si:$sp\n"); + update_stat("auth:amqp_async_error", "+1"); + send_reply("403", "Forbidden"); + exit; + } +} + +failure_route[KZ_AUTHORIZATION_CHECK_TIMEOUT] +{ + if($(kzR{kz.json,Event-Name}) == "message_returned" ) { + xlog("L_WARNING", "$ci|amqp|message was returned by broker $(kzR{kz.json,Error-Code}) $(kzR{kz.json,Error-Reason})\n"); + update_stat("auth:amqp_returned", "+1"); + } else { + xlog("L_WARNING", "$ci|end|failed $T_reply_code $T_reply_reason [$T(id_index):$T(id_label)] querying directory for authentication credentials for $Au $si:$sp\n"); + update_stat("auth:amqp_timeout", "+1"); + } + t_reply("403", "Forbidden"); + exit; +} + +onreply_route[KZ_AUTHORIZATION_CHECK_REPLY] +{ + $var(StartRoute) = $(TV(Sn){s.replace,.,}); + $var(delta_to_start) = $var(StartRoute) - $(kzR{kz.json,AMQP-Received}); + $var(delta_from_query) = $(kzR{kz.json,AMQP-Received}) - $xavp(deltas=>query); + xlog("L_INFO", "$ci|log|received $(kzR{kz.json,Event-Category}) $(kzR{kz.json,Event-Name}) reply from $(kzR{kz.json,App-Name})-$(kzR{kz.json,App-Version}) (Δ1 $(kzR{kz.json,AMQP-Elapsed-Micro}) μs , Δ2 $var(delta_to_start) μs, Δ3 $var(delta_from_query) μs)\n"); + $var(password) = $(kzR{kz.json,Auth-Password}); + if( $(kzR{kz.json,Event-Name}) == "authn_err" ) { + update_stat("auth:authn_err", "+1"); + t_reply("403", "Forbidden"); + exit; + } else if( $(kzR{kz.json,Event-Name}) == "authn_resp" ) { + update_stat("auth:authn_resp", "+1"); + route(KZ_AUTHORIZATION_CHECK_RESPONSE); + } else { + update_stat("auth:authn_unknown", "+1"); + xlog("L_INFO", "$ci|log|unhandle response from directory $Au via $(kzR{kz.json,App-Name})-$(kzR{kz.json,App-Version})\n"); + t_reply("403", "Forbidden"); + exit; + } +} + +route[KZ_AUTHORIZATION_CHECK_RESPONSE] +{ + if (!pv_auth_check("$fd", "$var(password)", "0", "0")) { + #!ifdef ANTIFLOOD_ROLE + route(ANITFLOOD_FAILED_AUTH); + #!endif + xlog("L_WARNING", "$ci|end|auth|$mbu\n"); + + send_reply("403", "Forbidden"); + exit; + } + + consume_credentials(); + route(SETUP_AUTH_ORIGIN); + $xavp(ulattrs=>custom_channel_vars) = $(kzR{kz.json,Custom-Channel-Vars}); + $xavp(ulattrs[0]=>token) = $_s($(kzR{kz.json,Custom-Channel-Vars.Authorizing-ID})@$(kzR{kz.json,Custom-Channel-Vars.Account-ID})); + setflag(FLAG_AUTHORIZED); + route(MAIN); + exit; +} + + +route[SETUP_AUTH_ORIGIN] +{ + $xavp(hf=>X-AUTH-IP) = $si; + $xavp(hf[0]=>X-AUTH-PORT) = $sp; +} + +route[SETUP_AUTH_AOR] +{ + if ($avp(is_registered) == "true") return; + + #!ifdef REGISTRAR_ROLE + $xavp(regcfg=>match_received) = $su; + if (registered("location","sip:$Au", 2, 1) == 1) { + $avp(is_registered) = "true"; + } + #!endif +} + +route[SETUP_AUTH_TRUSTED] +{ + + if (isflagset(FLAG_TRUSTED_SOURCE)) { + $xavp(hf[0]=>X-AUTH-Token) = $avp(trusted_x_header); + $xavp(hf[0]=>X-AUTH-URI-User) = $rU; + $xavp(hf[0]=>X-AUTH-URI-Realm) = $rd; + if(is_present_hf("P-Asserted-Identity") && $(ai{uri.user}) != "") { + $xavp(hf[0]=>X-AUTH-From-User) = $(ai{uri.user}); + } else if(is_present_hf("P-Preferred-Identity") && $pU != "") { + $xavp(hf[0]=>X-AUTH-From-User) = $pU; + } else if(is_present_hf("Remote-Party-ID") && $(re{uri.user}) != "") { + $xavp(hf[0]=>X-AUTH-From-User) = $(re{uri.user}); + } else { + $xavp(hf[0]=>X-AUTH-From-User) = $fU; + } + if($xavp(hf=>X-AUTH-From-User) =~ "^\+?00+$") { + $xavp(hf[0]=>X-AUTH-From-Is-Anonymous) = "true"; + $xavp(hf[0]=>X-AUTH-From-User) = $null; + } else if($(xavp(hf=>X-AUTH-From-User){s.tolower}) =~ "^anonymous$") { + $xavp(hf[0]=>X-AUTH-From-Is-Anonymous) = "true"; + $xavp(hf[0]=>X-AUTH-From-User) = $null; + } + setflag(FLAG_AUTHORIZED); + } + +} + +route[AUTH_HEADERS_JSON] +{ + xavp_params_implode("hf", "$var(outx)"); + $var(out) = $(var(outx){re.subst,/^(.*);$$/\1/}); + $var(c) = $(var(out){param.count}); + $var(headers_json) = ""; + $var(sep) = ""; + xlog("L_DEBUG", "$ci|auth|headers $var(c) => $var(out) => $var(outx)\n"); + while($var(c) > 0) { + $var(idx) = $var(c) - 1; + xlog("L_DEBUG", "$ci|auth|adding $(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\n"); + append_hf("$(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\r\n"); + $var(headers_json) = $_s($var(headers_json)$var(sep)"$(var(out){param.name,$var(idx)})" : "$(var(out){param.valueat,$var(idx)}{s.unescape.param})"); + $var(c) = $var(c) - 1; + $var(sep) = " , "; + } + $var(headers_json) = $_s({ $var(headers_json) }); +} + +route[AUTH_HEADERS] +{ + remove_hf_re("^X-"); + + if (!is_method("INVITE|MESSAGE|REFER")) { + return; + } + + xavp_params_implode("hf", "$var(outx)"); + $var(out) = $(var(outx){re.subst,/^(.*);$$/\1/}); + $var(c) = $(var(out){param.count}); + xlog("L_DEBUG", "$ci|auth|headers $var(c) => $var(out) => $var(outx)\n"); + while($var(c) > 0) { + $var(idx) = $var(c) - 1; + xlog("L_DEBUG", "$ci|auth|adding $(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\n"); + append_hf("$(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\r\n"); + $var(c) = $var(c) - 1; + } + +}