|
reSIProcate/repro
9694
|
#include <DigestAuthenticator.hxx>


Public Member Functions | |
| DigestAuthenticator (ProxyConfig &config, Dispatcher *authRequestDispatcher) | |
| ~DigestAuthenticator () | |
| virtual processor_action_t | process (RequestContext &) |
Private Member Functions | |
| bool | authorizedForThisIdentity (const resip::Data &user, const resip::Data &realm, resip::Uri &fromUri) |
| resip::NameAddr | getDefaultIdentity (const resip::Data &user, const resip::Data &realm, resip::NameAddr &from) |
| void | challengeRequest (RequestContext &, bool stale=false) |
| processor_action_t | requestUserAuthInfo (RequestContext &, resip::Data &realm) |
| virtual resip::Data | getRealm (RequestContext &) |
Private Attributes | |
| Dispatcher * | mAuthRequestDispatcher |
| bool | mNoIdentityHeaders |
| resip::Data | mHttpHostname |
| int | mHttpPort |
| bool | mUseAuthInt |
| bool | mRejectBadNonces |
Definition at line 16 of file DigestAuthenticator.hxx.
| DigestAuthenticator::DigestAuthenticator | ( | ProxyConfig & | config, |
| Dispatcher * | authRequestDispatcher | ||
| ) |
Definition at line 30 of file DigestAuthenticator.cxx.
: Processor("DigestAuthenticator"), mAuthRequestDispatcher(authRequestDispatcher), mNoIdentityHeaders(config.getConfigBool("DisableIdentity", false)), mHttpHostname(config.getConfigData("HttpHostname", "")), mHttpPort(config.getConfigInt("HttpPort", 5080)), mUseAuthInt(!config.getConfigBool("DisableAuthInt", false)), mRejectBadNonces(config.getConfigBool("RejectBadNonces", false)) { }
| DigestAuthenticator::~DigestAuthenticator | ( | ) |
Definition at line 42 of file DigestAuthenticator.cxx.
{
}
| bool DigestAuthenticator::authorizedForThisIdentity | ( | const resip::Data & | user, |
| const resip::Data & | realm, | ||
| resip::Uri & | fromUri | ||
| ) | [private] |
Definition at line 296 of file DigestAuthenticator.cxx.
{
// !rwm! good enough for now. TODO eventually consult a database to see what
// combinations of user/realm combos are authorized for an identity
if (fromUri.host() == realm)
{
if ((fromUri.user() == user) || (fromUri.user() == "anonymous"))
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 false;
}
| void DigestAuthenticator::challengeRequest | ( | repro::RequestContext & | rc, |
| bool | stale = false |
||
| ) | [private] |
Definition at line 330 of file DigestAuthenticator.cxx.
{
SipMessage &sipMessage = rc.getOriginalRequest();
Data realm = getRealm(rc);
SipMessage *challenge = Helper::makeProxyChallenge(sipMessage, realm,
mUseAuthInt /*auth-int*/, stale);
rc.sendResponse(*challenge);
delete challenge;
}
| NameAddr DigestAuthenticator::getDefaultIdentity | ( | const resip::Data & | user, |
| const resip::Data & | realm, | ||
| resip::NameAddr & | from | ||
| ) | [private] |
Definition at line 319 of file DigestAuthenticator.cxx.
| resip::Data DigestAuthenticator::getRealm | ( | RequestContext & | rc | ) | [private, virtual] |
Definition at line 396 of file DigestAuthenticator.cxx.
{
Data realm;
Proxy &proxy = rc.getProxy();
SipMessage& sipMessage = rc.getOriginalRequest();
// (1) Check Preferred Identity
if (sipMessage.exists(h_PPreferredIdentities))
{
// !abr! Add this when we get a chance
// find the fist sip or sips P-Preferred-Identity header
// for (;;)
// {
// if ((i->uri().scheme() == Symbols::SIP) || (i->uri().scheme() == Symbols::SIPS))
// {
// return i->uri().host();
// }
// }
}
// (2) Check From domain
if (proxy.isMyDomain(sipMessage.header(h_From).uri().host()))
{
return sipMessage.header(h_From).uri().host();
}
// (3) Check Top Route Header
if (sipMessage.exists(h_Routes) &&
sipMessage.header(h_Routes).size()!=0 &&
sipMessage.header(h_Routes).front().isWellFormed())
{
// !abr! Add this when we get a chance
}
// (4) Punt: Use Request URI
return sipMessage.header(h_RequestLine).uri().host();
}
| repro::Processor::processor_action_t DigestAuthenticator::process | ( | repro::RequestContext & | rc | ) | [virtual] |
Implements repro::Processor.
Definition at line 47 of file DigestAuthenticator.cxx.
{
DebugLog(<< "Monkey handling request: " << *this << "; reqcontext = " << rc);
Message *message = rc.getCurrentEvent();
SipMessage *sipMessage = dynamic_cast<SipMessage*>(message);
UserInfoMessage *userInfo = dynamic_cast<UserInfoMessage*>(message);
Proxy &proxy = rc.getProxy();
if (sipMessage)
{
if (sipMessage->method() == ACK ||
sipMessage->method() == BYE)
{
// Don't challenge ACK and BYE requests
return Continue;
}
if (sipMessage->exists(h_ProxyAuthorizations))
{
Auths &authHeaders = sipMessage->header(h_ProxyAuthorizations);
// if we find a Proxy-Authorization header for a realm we handle,
// asynchronously fetch the relevant userAuthInfo from the database
for (Auths::iterator i = authHeaders.begin() ; i != authHeaders.end() ; ++i)
{
// !rwm! TODO sometime we need to have a separate isMyRealm() function
if (proxy.isMyDomain(i->param(p_realm)))
{
return requestUserAuthInfo(rc, i->param(p_realm));
}
}
}
// if there was no Proxy-Auth header already, and the request is purportedly From
// one of our domains, send a challenge, unless this is from a trusted node in one
// of "our" domains (ex: from a gateway).
//
// Note that other monkeys can still challenge the request later if needed
// for other reasons (for example, the StaticRoute monkey)
if(!sipMessage->header(h_From).isWellFormed() ||
sipMessage->header(h_From).isAllContacts() )
{
InfoLog(<<"Malformed From header: cannot get realm to challenge with. Rejecting.");
rc.sendResponse(*auto_ptr<SipMessage>
(Helper::makeResponse(*sipMessage, 400, "Malformed From header")));
return SkipAllChains;
}
if (proxy.isMyDomain(sipMessage->header(h_From).uri().host()))
{
if (!rc.getKeyValueStore().getBoolValue(IsTrustedNode::mFromTrustedNodeKey))
{
challengeRequest(rc, false);
return SkipAllChains;
}
}
}
else if (userInfo)
{
// Handle response from user authentication database
sipMessage = &rc.getOriginalRequest();
const Data& a1 = userInfo->A1();
const Data& realm = userInfo->realm();
const Data& user = userInfo->user();
InfoLog (<< "Received user auth info for " << user << " at realm " << realm
<< " a1 is " << a1);
pair<Helper::AuthResult,Data> result =
Helper::advancedAuthenticateRequest(*sipMessage, realm, a1, 3000); // was 15
// Auths &authHeaders = sipMessage->header(h_ProxyAuthorizations);
switch (result.first)
{
case Helper::Failed:
InfoLog (<< "Authentication failed for " << user << " at realm " << realm << ". Sending 403");
rc.sendResponse(*auto_ptr<SipMessage>
(Helper::makeResponse(*sipMessage, 403, "Authentication Failed")));
return SkipAllChains;
// !abr! Eventually, this should just append a counter to
// the nonce, and increment it on each challenge.
// If this count is smaller than some reasonable limit,
// then we re-challenge; otherwise, we send a 403 instead.
case Helper::Authenticated:
InfoLog (<< "Authentication ok for " << user);
// Delete the Proxy-Auth header for this realm.
// other Proxy-Auth headers might be needed by a downsteram node
/*
Auths::iterator i = authHeaders.begin();
Auths::iterator j = authHeaders.begin();
while( i != authHeaders.end() )
{
if (proxy.isMyDomain(i->param(p_realm)))
{
j = i++;
authHeaders.erase(j);
}
else
{
++i;
}
}
*/
if(!sipMessage->header(h_From).isWellFormed() ||
sipMessage->header(h_From).isAllContacts())
{
InfoLog(<<"From header is malformed in"
" digest response.");
rc.sendResponse(*auto_ptr<SipMessage>
(Helper::makeResponse(*sipMessage, 400, "Malformed From header")));
return SkipAllChains;
}
if (authorizedForThisIdentity(user, realm, sipMessage->header(h_From).uri()))
{
rc.setDigestIdentity(user);
if(rc.getProxy().isPAssertedIdentityProcessingEnabled())
{
if (sipMessage->exists(h_PPreferredIdentities))
{
// Ensure any P-AssertedIdentities present are removed (note: this is an illegal condidition)
sipMessage->remove(h_PAssertedIdentities);
// TODO - when we have a concept of multiple identities per user
// find the first sip or sips P-Preferred-Identity header and the first tel
// bool haveSip = false;
// bool haveTel = false;
// for (;;)
// {
// if ((i->uri().scheme() == Symbols::SIP) || (i->uri().scheme() == Symbols::SIPS))
// {
// if (haveSip)
// {
// continue; // skip all but the first sip: or sips: URL
// }
// haveSip = true;
//
// if (knownSipIdentity( user, realm, i->uri() ) // should be NameAddr?
// {
// sipMessage->header(h_PAssertedIdentities).push_back( i->uri() );
// }
// else
// {
// sipMessage->header(h_PAssertedIdentities).push_back(getDefaultIdentity(user, realm));
// }
// }
// else if ((i->uri().scheme() == Symbols::TEL))
// {
// if (haveTel)
// {
// continue; // skip all but the first tel: URL
// }
// haveTel = true;
//
// if (knownTelIdentity( user, realm, i->uri() ))
// {
// sipMessage->header(h_PAssertedIdentities).push_back( i->uri() );
// }
// }
// }
// We currently don't do anything special with the P-Peferred-Identity hint - just
// add default identity
sipMessage->header(h_PAssertedIdentities).push_back(getDefaultIdentity(user, realm, sipMessage->header(h_From)));
// Remove the P-Preferered-Identity header
sipMessage->remove(h_PPreferredIdentities);
}
else
{
if (!sipMessage->exists(h_PAssertedIdentities))
{
sipMessage->header(h_PAssertedIdentities).push_back(getDefaultIdentity(user, realm, sipMessage->header(h_From)));
}
// else TODO
// - should implement guidlines in RFC5876 4.5 - whereby the proxy should remove
// ignored URI's (ie. a 2nd SIP, SIPS or TEL URI, unknown scheme)
}
}
#if defined(USE_SSL)
if(!mNoIdentityHeaders)
{
static Data http("http://" + mHttpHostname + ":" + Data(mHttpPort) + "/cert?domain=");
// .bwc. Leave pre-existing Identity headers alone.
if(!sipMessage->exists(h_Identity))
{
sipMessage->header(h_Identity).value() = Data::Empty; // This is a signal to have the TransportSelector fill in the identity header
if(sipMessage->exists(h_IdentityInfo))
{
InfoLog(<<"Somebody sent us a"
" request with an Identity-Info, but no Identity"
" header. Removing it.");
if(!sipMessage->header(h_IdentityInfo).isWellFormed())
{
InfoLog(<<"...and this "
"Identity-Info header was malformed!");
}
sipMessage->remove(h_IdentityInfo);
}
sipMessage->header(h_IdentityInfo).uri() = http + realm;
InfoLog (<< "Identity-Info=" << sipMessage->header(h_IdentityInfo).uri());
}
}
#endif
}
else
{
// !rwm! The user is trying to forge a request. Respond with a 403
InfoLog (<< "User: " << user << " at realm: " << realm <<
" trying to forge request from: " << sipMessage->header(h_From).uri());
rc.sendResponse(*auto_ptr<SipMessage>
(Helper::makeResponse(*sipMessage, 403)));
return SkipAllChains;
}
return Continue;
case Helper::Expired:
InfoLog (<< "Authentication expired for " << user);
challengeRequest(rc, true);
return SkipAllChains;
case Helper::BadlyFormed:
InfoLog (<< "Authentication nonce badly formed for " << user);
if(mRejectBadNonces)
{
rc.sendResponse(*auto_ptr<SipMessage>
(Helper::makeResponse(*sipMessage, 403, "Where on earth did you get that nonce?")));
}
else
{
challengeRequest(rc, true);
}
return SkipAllChains;
}
}
return Continue;
}
| repro::Processor::processor_action_t DigestAuthenticator::requestUserAuthInfo | ( | repro::RequestContext & | rc, |
| resip::Data & | realm | ||
| ) | [private] |
Definition at line 344 of file DigestAuthenticator.cxx.
{
Message *message = rc.getCurrentEvent();
SipMessage *sipMessage = dynamic_cast<SipMessage*>(message);
assert(sipMessage);
// Extract the user from the appropriate Proxy-Authorization header
Auths &authorizationHeaders = sipMessage->header(h_ProxyAuthorizations);
Auths::iterator i;
Data user;
for (i = authorizationHeaders.begin();
i != authorizationHeaders.end(); i++)
{
if ( i->exists(p_realm) &&
i->param(p_realm) == realm
&& i->exists(p_username))
{
user = i->param(p_username);
InfoLog (<< "Request user auth info for " << user
<< " at realm " << realm);
break;
}
}
if (!user.empty())
{
UserInfoMessage* async = new UserInfoMessage(*this, rc.getTransactionId(), &(rc.getProxy()));
async->user()=user;
async->realm()=realm;
if(sipMessage->header(h_From).isWellFormed())
{
async->domain()=sipMessage->header(h_From).uri().host();
}
else
{
async->domain()=realm;
}
std::auto_ptr<ApplicationMessage> app(async);
mAuthRequestDispatcher->post(app);
return WaitingForEvent;
}
else
{
challengeRequest(rc, false);
return SkipAllChains;
}
}
Definition at line 31 of file DigestAuthenticator.hxx.
Definition at line 33 of file DigestAuthenticator.hxx.
int repro::DigestAuthenticator::mHttpPort [private] |
Definition at line 34 of file DigestAuthenticator.hxx.
bool repro::DigestAuthenticator::mNoIdentityHeaders [private] |
Definition at line 32 of file DigestAuthenticator.hxx.
bool repro::DigestAuthenticator::mRejectBadNonces [private] |
Definition at line 36 of file DigestAuthenticator.hxx.
bool repro::DigestAuthenticator::mUseAuthInt [private] |
Definition at line 35 of file DigestAuthenticator.hxx.
1.7.5.1