背景
这两个模块用于账号认证的,auth_db
模块必须和auth
模块一起,不能独立使用。
auth_db
要使用数据库存储账号信息.和上一章kamailio
的这个两个模块功能相同。
相对于kamailio
,opensips
支持RFC 8760
更强的密码认证(SHA-512-256
)
官方文档地址:
- auth
- auth_db
本次测试的opensips版本是:
version: opensips 3.3.10 (x86_64/linux)
auth 模块
参数解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# 计算nonce的密钥,默认是随机生成的字符串
modparam("auth", "secret", "johndoessecretphrase")
# 设置nonce的过期时间,单位s,默认:300s
modparam("auth", "nonce_expire", 15)
# 为Remote-Party-ID添加前缀
modparam("auth", "rpid_prefix", "Whatever <")
# 为Remote-Party-ID添加后缀
modparam("auth", "rpid_suffix", "@1.2.3.4>")
# 设置realm自动删除的前缀,默认:""
modparam("auth", "realm_prefix", "sip.")
# avp变量存储RPID,默认:"$avp(rpid)"
modparam("auth", "rpid_avp", "$avp(caller_rpid)")
# 用户名存储在avp变量中,默认:"NULL"
modparam("auth", "username_spec", "$var(username)")
# 密码存储在avp变量中,默认:"NULL"
modparam("auth", "password_spec", "$var(password)")
# 密码是否使用HA1格式.
modparam("auth", "calculate_ha1", 1)
|
主要函数
www_challenge(realm[, qop[, algorithms]])
生成WWW-Authorize
头部给响应,algorithms
默认md5
。
proxy_challenge(realm[, qop[, algorithms]])
生成Proxy-Authorize
头部给响应,参数和www_challenge
一样。
consume_credentials()
删除认证信息,比如:删除Authorize
头部,删除Proxy-Authorize
头部. 必须在www_authorize()
或者proxy_authorize()
之后调用。
is_rpid_user_e164()
检查Remote-Party-ID
是否是E164格式。
append_rpid_hf()
追加SIP URI到Remote-Party-ID
头部字段。
append_rpid_hf(prefix, suffix)
追加前后缀到Remote-Party-ID
头部字段。
pv_www_authorize(realm)
验证credentials
是否正确,如果正确,标记此credentials
已经验证了,如果失败,后面可以主动调用www_challenge()
再次请求验证。
- 返回值:
- -5: 通用错误,不发送回复
- -4: 请求没有credentials
- -3: nonce状态
- -2: 密码错误
- -1: 用户名错误
pv_proxy_authorize(realm)
验证credentials
是否正确,如果正确,标记此credentials
已经验证了,如果失败,后面可以主动调用proxy_challenge()
再次请求验证。
auth_db 模块
使用到的数据表subscriber
和uri
参数解析
1
2
3
4
5
6
7
8
9
10
|
# 数据库连接
modparam("auth_db", "db_url", "DBURL")
# 是否使用HA1格式的密码来认证
modparam("auth_db", "calculate_ha1", 1)
# 是否使用domain
modparam("auth_db", "use_domain", 1)
# 设置是否加载credentials到avp变量,默认:""
modparam("auth_db", "load_credentials", "$avp(13)=rpid;email_address")
# 设置是否跳过版本检查,默认:0
modparam("auth_db", "skip_version_check", 1)
|
主要函数
www_authorize(realm, table)
验证credentials
是否正确,如果正确,标记此credentials
已经验证了,如果失败,后面可以主动调用www_challenge()
再次请求验证。
proxy_authorize(realm, table)
验证credentials
是否正确,如果正确,标记此credentials
已经验证了,如果失败,后面可以主动调用proxy_challenge()
再次请求验证。
入参,返回值和www_authorize
一样。
db_is_to_authorized(table)
检查To
头部的URI
是否是授权的。
db_is_from_authorized(table)
检查From
头部的URI
是否是授权的。
db_does_uri_exist(uri, table)
检查 username@domain
是否存在subscriber
表中
db_get_auth_id(table, uri, auth, realm)
检查uri
是否存在subscriber
表中.
实战
不使用数据库
配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
socket=udp:172.16.4.111:5261
...
loadmodule "auth.so"
modparam("auth", "nonce_expire", 60)
modparam("auth", "username_spec", "$var(username)")
modparam("auth", "password_spec", "$var(password)")
modparam("auth", "calculate_ha1", 1)
route {
...
if (is_method("REGISTER")) {
$var(username)="1007";
$var(password)="1234";
if (!pv_www_authorize("")) {
www_challenge("", "auth,auth-int");
exit;
}
# indicate that the client supports DTLS
# so we know when he is called
if (isflagset("SRC_WS"))
setbflag("DST_WS");
fix_nated_register();
if (!save("location"))
sl_reply_error();
exit;
}
if (!lookup("location","m")) {
t_newtran();
t_reply(404, "Not Found");
exit;
}
route(relay);
}
|
说明: 如果要使用SHA-512-256
及SHA-512-256-sess
算法,openssl
需要升级版本>=1.1.1
, 否则会报错。
1
2
3
|
core:dauth_fixup_algorithms: Unsupported algorithm type: "SHA-512-256"
May 26 14:24:13 [242] ERROR:core:fix_cmd: Fixup failed for param [3]
May 26 14:24:13 [242] ERROR:core:fix_actions: Failed to fix command <www_challenge>
|
输出结果
- 使用软电话注册号码1007,密码1234,注册成功:

可以看到在401
信令上,WWW-Authenticate
头部包含qop
和algorithm
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
route {
if (is_method("REGISTER")) {
$var(username)="1007";
$var(password)="1234";
if (!pv_proxy_authorize("")) {
proxy_challenge("", "auth,auth-int","SHA-256"); # Realm will be autogenerated
exit;
}
# indicate that the client supports DTLS
# so we know when he is called
if (isflagset("SRC_WS"))
setbflag("DST_WS");
fix_nated_register();
if (!save("location"))
sl_reply_error();
exit;
}
}
|
输出的信令图:

可以看到在407
信令上,Proxy-Authenticate
头部包含qop
和algorithm
。
使用数据库
配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
socket=udp:172.16.4.111:5261
...
loadmodule "auth.so"
modparam("auth", "nonce_expire", 60)
modparam("auth", "username_spec", "$var(username)")
modparam("auth", "password_spec", "$var(password)")
#modparam("auth", "calculate_ha1", 1)
loadmodule "auth_db.so"
modparam("auth_db", "db_url", "DBURL")
#modparam("auth_db", "calculate_ha1", 1)
route {
...
if (is_method("REGISTER")) {
if (!www_authorize("", "subscriber")) {
www_challenge("", "auth","SHA-256");
exit;
}
# indicate that the client supports DTLS
# so we know when he is called
if (isflagset("SRC_WS"))
setbflag("DST_WS");
fix_nated_register();
if (!save("location"))
sl_reply_error();
exit;
}
}
|
数据表subscriber
的结构为:

ha1
字段的计算方式: md5(username:realm:password)
ha1_sha256
字段的计算方式: sha256(username:realm:password)
ha1_sha512t256
字段的计算方式: sha512t256(username:realm:password)
添加用户:
- 使用
opensips-cli
客户端创建用户:
1
|
opensips-cli -f ./opensips-cli.cfg -x user add 1007@172.16.4.111 1234
|
- 直接在数据表添加用户:
1
|
insert into subcriber ('username','domain','password','ha1','ha1_sha256')values('1007','172.16.4.111','1234','167f7cc6ce5f65305e413cd7d040cce3','467bd26ba1d413546561c0f3c32cd85f1c162ee84c19acb687efc6faa6c11266')
|
输出结果
使用md5
算法,注册成功:

如果使用HA1
算法,放开配置modparam("auth_db", "calculate_ha1", 1)
,目前未注册成功:

日志报错:

一直报错:sha256认证失败, 但是数据库中ha1_sha256
字段的值是正确的。暂时未找到问题所在。
总结
opensips
在不使用数据库的情况下, 用户名和密码都要设置, kamailio
只设置密码。
opensips
支持MD5
,SHA-256
和SHA-512-256
算法, kamailio
支持MD5
,SHA-256
算法。