repro为resiprocate 提供的代理服务,可以直接运行,我们可以参考他,来实现自己的sip服务,下面分析一下repro关于digest流程的处理。
找到工程reprolib的ReproServerAuthManager 类,处理digest认证再此类完成。
首先进入,这里返回true 表示digest 认证
ServerAuthManager::AsyncBool
ReproServerAuthManager::requiresChallenge(const SipMessage& msg)
{
resip_assert(msg.isRequest());
if(!mAclDb.isRequestTrusted(msg))
{
return ServerAuthManager::requiresChallenge(msg);
}
else
{
return False;
}
}
然后进入requestCredential函数
void
ReproServerAuthManager::requestCredential(const Data& user,
const Data& realm,
const SipMessage& msg,
const Auth& auth,
const Data& transactionId )
{
// Build a UserAuthInfo object and pass to UserAuthGrabber to have a1 password filled in
UserAuthInfo* async = new UserAuthInfo(user,realm,transactionId,&mDum);
std::auto_ptr<ApplicationMessage> app(async);
mAuthRequestDispatcher->post(app);
}
这个函数的作用是获取A1值,A1说明如下
采用MD5算法:
A1=(user):(realm):(password)
我们自己开发服务的时候,可以直接在这里获取A1的值,反馈给dum,
repro 在UserAuthGrabber::process函数获取A1的值,其实就是从数据库里面把A1的值拿出来。
UserAuthGrabber::process(resip::ApplicationMessage* msg)
{
repro::UserInfoMessage* uinf = dynamic_cast<UserInfoMessage*>(msg); // auth for repro's DigestAuthenticator
if (uinf)
{
uinf->mRec.passwordHash = mUserStore.getUserAuthInfo(uinf->user(), uinf->realm());
uinf->setMode(resip::UserAuthInfo::RetrievedA1);
DebugLog(<< "Grabbed user info for " << uinf->user() << "@" << uinf->realm() << " : " << uinf->A1());
return true;
}
resip::UserAuthInfo* uainf = dynamic_cast<resip::UserAuthInfo*>(msg); // auth for DUM's ServerAuthManager
if (uainf)
{
uainf->setA1(mUserStore.getUserAuthInfo(uainf->getUser(), uainf->getRealm()));
if (uainf->getA1().empty())
{
uainf->setMode(resip::UserAuthInfo::UserUnknown);
}
DebugLog(<< "Grabbed user info for " << uainf->getUser() << "@" << uainf->getRealm() << " : " << uainf->getA1());
return true;
}
repro::PresenceUserExists* pue = dynamic_cast<repro::PresenceUserExists*>(msg); // user exists query for Presence server
if (pue)
{
pue->setUserExists(!mUserStore.getUserInfo(UserStore::buildKey(pue->getUser(), pue->getDomain())).user.empty());
DebugLog(<< "Checking existence for " << pue->getUser() << "@" << pue->getDomain() << " : user " << (pue->getUserExists() ? "exists" : "does not exist"));
return true;
}
WarningLog(<< "Did not recognize message type...");
return false;
}
获取A1值之后调用
mStack->post
投递给协议栈,即可完成注册流程的服务端开发。
queueToStack = mWorker->process(msg);
if(queueToStack && mStack)
{
StackLog(<<"async work done, posting to stack");
// Post to stack instead of directly to TU, since stack does
// some safety checks to ensure the TU still exists before posting
mStack->post(std::auto_ptr<resip::ApplicationMessage>(msg));
}
****************-------我是风格线--------****************************
用海康摄像机,测试注册功能,如下图,发现一个大问题,当sip用户名和sip用户认证ID填写一样时,可以认证通过
但是当这两者不一样时,认证失败,抓包显示未知用户。
通过阅读源码,发现在校验结束后,还校验了from字段的用户名和认证用户名是否一样,强制修改为return true后,认证通过。
为什么一定要from字段的用户名和认证用户名一样呢?不得而知。
bool
ServerAuthManager::authorizedForThisIdentity(const resip::Data &user,
const resip::Data &realm,
resip::Uri &fromUri)
{
// !rwm! good enough for now. TODO eventually consult a database to see what
// combinations of user/realm combos are authorized for an identity
// First try the form where the username parameter in the auth
// header is just the username component of the fromUri
//
if ((fromUri.user() == user) && (fromUri.host() == realm))
return true;
// Now try the form where the username parameter in the auth
// header is the full fromUri, e.g.
// Proxy-Authorization: Digest username="user@domain" ...
//
if (fromUri.getAorNoPort() == user)
return true;
// catch-all: access denied
return true;
}
附上抓包截图
*****************************************resip注册处理流程******************************************
今天遇到了sip注册发生了405的错误
查明原因,注册管理,需要设置RegistrationPersistenceManager类,由于我没有设置,所以返回405失败。
增加RegistrationPersistenceManager属性
InMemorySyncRegDb* pRegDB = new InMemorySyncRegDb(0);
mDum->setRegistrationPersistenceManager(pRegDB);
另外发现一个调试的好方法:找到错误码的对应类,打上断点,基本上就可以处理基本的错误。