|
reSIProcate/repro
9694
|
00001 00002 #if defined(HAVE_CONFIG_H) 00003 #include "config.h" 00004 #endif 00005 00006 #include "rutil/DnsUtil.hxx" 00007 #include "resip/stack/Message.hxx" 00008 #include "resip/stack/SipMessage.hxx" 00009 #include "resip/stack/Auth.hxx" 00010 #include "resip/stack/Helper.hxx" 00011 #include "rutil/Logger.hxx" 00012 00013 #include "repro/monkeys/DigestAuthenticator.hxx" 00014 #include "repro/monkeys/IsTrustedNode.hxx" 00015 #include "repro/RequestContext.hxx" 00016 #include "repro/Proxy.hxx" 00017 #include "repro/UserInfoMessage.hxx" 00018 #include "repro/UserStore.hxx" 00019 #include "repro/Dispatcher.hxx" 00020 #include "resip/stack/SipStack.hxx" 00021 #include "rutil/ParseBuffer.hxx" 00022 #include "rutil/WinLeakCheck.hxx" 00023 00024 #define RESIPROCATE_SUBSYSTEM resip::Subsystem::REPRO 00025 00026 using namespace resip; 00027 using namespace repro; 00028 using namespace std; 00029 00030 DigestAuthenticator::DigestAuthenticator(ProxyConfig& config, 00031 Dispatcher* authRequestDispatcher) : 00032 Processor("DigestAuthenticator"), 00033 mAuthRequestDispatcher(authRequestDispatcher), 00034 mNoIdentityHeaders(config.getConfigBool("DisableIdentity", false)), 00035 mHttpHostname(config.getConfigData("HttpHostname", "")), 00036 mHttpPort(config.getConfigInt("HttpPort", 5080)), 00037 mUseAuthInt(!config.getConfigBool("DisableAuthInt", false)), 00038 mRejectBadNonces(config.getConfigBool("RejectBadNonces", false)) 00039 { 00040 } 00041 00042 DigestAuthenticator::~DigestAuthenticator() 00043 { 00044 } 00045 00046 repro::Processor::processor_action_t 00047 DigestAuthenticator::process(repro::RequestContext &rc) 00048 { 00049 DebugLog(<< "Monkey handling request: " << *this << "; reqcontext = " << rc); 00050 00051 Message *message = rc.getCurrentEvent(); 00052 00053 SipMessage *sipMessage = dynamic_cast<SipMessage*>(message); 00054 UserInfoMessage *userInfo = dynamic_cast<UserInfoMessage*>(message); 00055 Proxy &proxy = rc.getProxy(); 00056 00057 if (sipMessage) 00058 { 00059 if (sipMessage->method() == ACK || 00060 sipMessage->method() == BYE) 00061 { 00062 // Don't challenge ACK and BYE requests 00063 return Continue; 00064 } 00065 00066 if (sipMessage->exists(h_ProxyAuthorizations)) 00067 { 00068 Auths &authHeaders = sipMessage->header(h_ProxyAuthorizations); 00069 00070 // if we find a Proxy-Authorization header for a realm we handle, 00071 // asynchronously fetch the relevant userAuthInfo from the database 00072 for (Auths::iterator i = authHeaders.begin() ; i != authHeaders.end() ; ++i) 00073 { 00074 // !rwm! TODO sometime we need to have a separate isMyRealm() function 00075 if (proxy.isMyDomain(i->param(p_realm))) 00076 { 00077 return requestUserAuthInfo(rc, i->param(p_realm)); 00078 } 00079 } 00080 } 00081 00082 // if there was no Proxy-Auth header already, and the request is purportedly From 00083 // one of our domains, send a challenge, unless this is from a trusted node in one 00084 // of "our" domains (ex: from a gateway). 00085 // 00086 // Note that other monkeys can still challenge the request later if needed 00087 // for other reasons (for example, the StaticRoute monkey) 00088 if(!sipMessage->header(h_From).isWellFormed() || 00089 sipMessage->header(h_From).isAllContacts() ) 00090 { 00091 InfoLog(<<"Malformed From header: cannot get realm to challenge with. Rejecting."); 00092 rc.sendResponse(*auto_ptr<SipMessage> 00093 (Helper::makeResponse(*sipMessage, 400, "Malformed From header"))); 00094 return SkipAllChains; 00095 } 00096 00097 if (proxy.isMyDomain(sipMessage->header(h_From).uri().host())) 00098 { 00099 if (!rc.getKeyValueStore().getBoolValue(IsTrustedNode::mFromTrustedNodeKey)) 00100 { 00101 challengeRequest(rc, false); 00102 return SkipAllChains; 00103 } 00104 } 00105 } 00106 else if (userInfo) 00107 { 00108 // Handle response from user authentication database 00109 sipMessage = &rc.getOriginalRequest(); 00110 const Data& a1 = userInfo->A1(); 00111 const Data& realm = userInfo->realm(); 00112 const Data& user = userInfo->user(); 00113 InfoLog (<< "Received user auth info for " << user << " at realm " << realm 00114 << " a1 is " << a1); 00115 00116 pair<Helper::AuthResult,Data> result = 00117 Helper::advancedAuthenticateRequest(*sipMessage, realm, a1, 3000); // was 15 00118 00119 // Auths &authHeaders = sipMessage->header(h_ProxyAuthorizations); 00120 switch (result.first) 00121 { 00122 case Helper::Failed: 00123 InfoLog (<< "Authentication failed for " << user << " at realm " << realm << ". Sending 403"); 00124 rc.sendResponse(*auto_ptr<SipMessage> 00125 (Helper::makeResponse(*sipMessage, 403, "Authentication Failed"))); 00126 return SkipAllChains; 00127 00128 // !abr! Eventually, this should just append a counter to 00129 // the nonce, and increment it on each challenge. 00130 // If this count is smaller than some reasonable limit, 00131 // then we re-challenge; otherwise, we send a 403 instead. 00132 00133 case Helper::Authenticated: 00134 InfoLog (<< "Authentication ok for " << user); 00135 00136 // Delete the Proxy-Auth header for this realm. 00137 // other Proxy-Auth headers might be needed by a downsteram node 00138 /* 00139 Auths::iterator i = authHeaders.begin(); 00140 Auths::iterator j = authHeaders.begin(); 00141 while( i != authHeaders.end() ) 00142 { 00143 if (proxy.isMyDomain(i->param(p_realm))) 00144 { 00145 j = i++; 00146 authHeaders.erase(j); 00147 } 00148 else 00149 { 00150 ++i; 00151 } 00152 } 00153 */ 00154 if(!sipMessage->header(h_From).isWellFormed() || 00155 sipMessage->header(h_From).isAllContacts()) 00156 { 00157 InfoLog(<<"From header is malformed in" 00158 " digest response."); 00159 rc.sendResponse(*auto_ptr<SipMessage> 00160 (Helper::makeResponse(*sipMessage, 400, "Malformed From header"))); 00161 return SkipAllChains; 00162 } 00163 00164 if (authorizedForThisIdentity(user, realm, sipMessage->header(h_From).uri())) 00165 { 00166 rc.setDigestIdentity(user); 00167 00168 if(rc.getProxy().isPAssertedIdentityProcessingEnabled()) 00169 { 00170 if (sipMessage->exists(h_PPreferredIdentities)) 00171 { 00172 // Ensure any P-AssertedIdentities present are removed (note: this is an illegal condidition) 00173 sipMessage->remove(h_PAssertedIdentities); 00174 00175 // TODO - when we have a concept of multiple identities per user 00176 // find the first sip or sips P-Preferred-Identity header and the first tel 00177 // bool haveSip = false; 00178 // bool haveTel = false; 00179 // for (;;) 00180 // { 00181 // if ((i->uri().scheme() == Symbols::SIP) || (i->uri().scheme() == Symbols::SIPS)) 00182 // { 00183 // if (haveSip) 00184 // { 00185 // continue; // skip all but the first sip: or sips: URL 00186 // } 00187 // haveSip = true; 00188 // 00189 // if (knownSipIdentity( user, realm, i->uri() ) // should be NameAddr? 00190 // { 00191 // sipMessage->header(h_PAssertedIdentities).push_back( i->uri() ); 00192 // } 00193 // else 00194 // { 00195 // sipMessage->header(h_PAssertedIdentities).push_back(getDefaultIdentity(user, realm)); 00196 // } 00197 // } 00198 // else if ((i->uri().scheme() == Symbols::TEL)) 00199 // { 00200 // if (haveTel) 00201 // { 00202 // continue; // skip all but the first tel: URL 00203 // } 00204 // haveTel = true; 00205 // 00206 // if (knownTelIdentity( user, realm, i->uri() )) 00207 // { 00208 // sipMessage->header(h_PAssertedIdentities).push_back( i->uri() ); 00209 // } 00210 // } 00211 // } 00212 00213 // We currently don't do anything special with the P-Peferred-Identity hint - just 00214 // add default identity 00215 sipMessage->header(h_PAssertedIdentities).push_back(getDefaultIdentity(user, realm, sipMessage->header(h_From))); 00216 00217 // Remove the P-Preferered-Identity header 00218 sipMessage->remove(h_PPreferredIdentities); 00219 } 00220 else 00221 { 00222 if (!sipMessage->exists(h_PAssertedIdentities)) 00223 { 00224 sipMessage->header(h_PAssertedIdentities).push_back(getDefaultIdentity(user, realm, sipMessage->header(h_From))); 00225 } 00226 // else TODO 00227 // - should implement guidlines in RFC5876 4.5 - whereby the proxy should remove 00228 // ignored URI's (ie. a 2nd SIP, SIPS or TEL URI, unknown scheme) 00229 } 00230 } 00231 00232 #if defined(USE_SSL) 00233 if(!mNoIdentityHeaders) 00234 { 00235 static Data http("http://" + mHttpHostname + ":" + Data(mHttpPort) + "/cert?domain="); 00236 // .bwc. Leave pre-existing Identity headers alone. 00237 if(!sipMessage->exists(h_Identity)) 00238 { 00239 sipMessage->header(h_Identity).value() = Data::Empty; // This is a signal to have the TransportSelector fill in the identity header 00240 if(sipMessage->exists(h_IdentityInfo)) 00241 { 00242 InfoLog(<<"Somebody sent us a" 00243 " request with an Identity-Info, but no Identity" 00244 " header. Removing it."); 00245 if(!sipMessage->header(h_IdentityInfo).isWellFormed()) 00246 { 00247 InfoLog(<<"...and this " 00248 "Identity-Info header was malformed!"); 00249 } 00250 00251 sipMessage->remove(h_IdentityInfo); 00252 } 00253 00254 sipMessage->header(h_IdentityInfo).uri() = http + realm; 00255 InfoLog (<< "Identity-Info=" << sipMessage->header(h_IdentityInfo).uri()); 00256 } 00257 } 00258 #endif 00259 } 00260 else 00261 { 00262 // !rwm! The user is trying to forge a request. Respond with a 403 00263 InfoLog (<< "User: " << user << " at realm: " << realm << 00264 " trying to forge request from: " << sipMessage->header(h_From).uri()); 00265 rc.sendResponse(*auto_ptr<SipMessage> 00266 (Helper::makeResponse(*sipMessage, 403))); 00267 return SkipAllChains; 00268 } 00269 00270 return Continue; 00271 00272 case Helper::Expired: 00273 InfoLog (<< "Authentication expired for " << user); 00274 challengeRequest(rc, true); 00275 return SkipAllChains; 00276 00277 case Helper::BadlyFormed: 00278 InfoLog (<< "Authentication nonce badly formed for " << user); 00279 if(mRejectBadNonces) 00280 { 00281 rc.sendResponse(*auto_ptr<SipMessage> 00282 (Helper::makeResponse(*sipMessage, 403, "Where on earth did you get that nonce?"))); 00283 } 00284 else 00285 { 00286 challengeRequest(rc, true); 00287 } 00288 return SkipAllChains; 00289 } 00290 } 00291 00292 return Continue; 00293 } 00294 00295 bool 00296 DigestAuthenticator::authorizedForThisIdentity(const resip::Data &user, const resip::Data &realm, 00297 resip::Uri &fromUri) 00298 { 00299 // !rwm! good enough for now. TODO eventually consult a database to see what 00300 // combinations of user/realm combos are authorized for an identity 00301 if (fromUri.host() == realm) 00302 { 00303 if ((fromUri.user() == user) || (fromUri.user() == "anonymous")) 00304 return true; 00305 00306 // Now try the form where the username parameter in the auth 00307 // header is the full fromUri, e.g. 00308 // Proxy-Authorization: Digest username="user@domain" ... 00309 // 00310 if (fromUri.getAorNoPort() == user) 00311 return true; 00312 } 00313 00314 // catch-all: access denied 00315 return false; 00316 } 00317 00318 NameAddr 00319 DigestAuthenticator::getDefaultIdentity(const resip::Data &user, const resip::Data &realm, resip::NameAddr &from) 00320 { 00321 NameAddr defaultIdentity; 00322 defaultIdentity.displayName() = from.displayName(); 00323 defaultIdentity.uri().scheme() = from.uri().scheme(); 00324 defaultIdentity.uri().user() = user; 00325 defaultIdentity.uri().host() = realm; 00326 return defaultIdentity; 00327 } 00328 00329 void 00330 DigestAuthenticator::challengeRequest(repro::RequestContext &rc, 00331 bool stale) 00332 { 00333 SipMessage &sipMessage = rc.getOriginalRequest(); 00334 Data realm = getRealm(rc); 00335 00336 SipMessage *challenge = Helper::makeProxyChallenge(sipMessage, realm, 00337 mUseAuthInt /*auth-int*/, stale); 00338 rc.sendResponse(*challenge); 00339 delete challenge; 00340 } 00341 00342 00343 repro::Processor::processor_action_t 00344 DigestAuthenticator::requestUserAuthInfo(repro::RequestContext &rc, resip::Data &realm) 00345 { 00346 Message *message = rc.getCurrentEvent(); 00347 SipMessage *sipMessage = dynamic_cast<SipMessage*>(message); 00348 assert(sipMessage); 00349 00350 00351 // Extract the user from the appropriate Proxy-Authorization header 00352 Auths &authorizationHeaders = sipMessage->header(h_ProxyAuthorizations); 00353 Auths::iterator i; 00354 Data user; 00355 00356 for (i = authorizationHeaders.begin(); 00357 i != authorizationHeaders.end(); i++) 00358 { 00359 if ( i->exists(p_realm) && 00360 i->param(p_realm) == realm 00361 && i->exists(p_username)) 00362 { 00363 user = i->param(p_username); 00364 00365 InfoLog (<< "Request user auth info for " << user 00366 << " at realm " << realm); 00367 break; 00368 } 00369 } 00370 00371 if (!user.empty()) 00372 { 00373 UserInfoMessage* async = new UserInfoMessage(*this, rc.getTransactionId(), &(rc.getProxy())); 00374 async->user()=user; 00375 async->realm()=realm; 00376 if(sipMessage->header(h_From).isWellFormed()) 00377 { 00378 async->domain()=sipMessage->header(h_From).uri().host(); 00379 } 00380 else 00381 { 00382 async->domain()=realm; 00383 } 00384 std::auto_ptr<ApplicationMessage> app(async); 00385 mAuthRequestDispatcher->post(app); 00386 return WaitingForEvent; 00387 } 00388 else 00389 { 00390 challengeRequest(rc, false); 00391 return SkipAllChains; 00392 } 00393 } 00394 00395 resip::Data 00396 DigestAuthenticator::getRealm(RequestContext &rc) 00397 { 00398 Data realm; 00399 00400 Proxy &proxy = rc.getProxy(); 00401 SipMessage& sipMessage = rc.getOriginalRequest(); 00402 00403 // (1) Check Preferred Identity 00404 if (sipMessage.exists(h_PPreferredIdentities)) 00405 { 00406 // !abr! Add this when we get a chance 00407 // find the fist sip or sips P-Preferred-Identity header 00408 // for (;;) 00409 // { 00410 // if ((i->uri().scheme() == Symbols::SIP) || (i->uri().scheme() == Symbols::SIPS)) 00411 // { 00412 // return i->uri().host(); 00413 // } 00414 // } 00415 } 00416 00417 // (2) Check From domain 00418 if (proxy.isMyDomain(sipMessage.header(h_From).uri().host())) 00419 { 00420 return sipMessage.header(h_From).uri().host(); 00421 } 00422 00423 // (3) Check Top Route Header 00424 if (sipMessage.exists(h_Routes) && 00425 sipMessage.header(h_Routes).size()!=0 && 00426 sipMessage.header(h_Routes).front().isWellFormed()) 00427 { 00428 // !abr! Add this when we get a chance 00429 } 00430 00431 // (4) Punt: Use Request URI 00432 return sipMessage.header(h_RequestLine).uri().host(); 00433 } 00434 00435 00436 /* ==================================================================== 00437 * The Vovida Software License, Version 1.0 00438 * 00439 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 00440 * 00441 * Redistribution and use in source and binary forms, with or without 00442 * modification, are permitted provided that the following conditions 00443 * are met: 00444 * 00445 * 1. Redistributions of source code must retain the above copyright 00446 * notice, this list of conditions and the following disclaimer. 00447 * 00448 * 2. Redistributions in binary form must reproduce the above copyright 00449 * notice, this list of conditions and the following disclaimer in 00450 * the documentation and/or other materials provided with the 00451 * distribution. 00452 * 00453 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00454 * and "Vovida Open Communication Application Library (VOCAL)" must 00455 * not be used to endorse or promote products derived from this 00456 * software without prior written permission. For written 00457 * permission, please contact vocal@vovida.org. 00458 * 00459 * 4. Products derived from this software may not be called "VOCAL", nor 00460 * may "VOCAL" appear in their name, without prior written 00461 * permission of Vovida Networks, Inc. 00462 * 00463 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00464 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00465 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00466 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00467 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00468 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00469 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00470 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00471 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00472 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00473 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00474 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00475 * DAMAGE. 00476 * 00477 * ==================================================================== 00478 * 00479 * This software consists of voluntary contributions made by Vovida 00480 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00481 * Inc. For more information on Vovida Networks, Inc., please see 00482 * <http://www.vovida.org/>. 00483 * 00484 */
1.7.5.1