|
reSIProcate/DialogUsageManager
9694
|
00001 #include <cassert> 00002 00003 #include "resip/dum/ChallengeInfo.hxx" 00004 #include "resip/dum/DumFeature.hxx" 00005 #include "resip/dum/DumFeatureChain.hxx" 00006 #include "resip/dum/ServerAuthManager.hxx" 00007 #include "resip/dum/DialogUsageManager.hxx" 00008 #include "resip/dum/TargetCommand.hxx" 00009 #include "rutil/Logger.hxx" 00010 #include "resip/dum/UserAuthInfo.hxx" 00011 #include "resip/stack/Helper.hxx" 00012 #include "rutil/WinLeakCheck.hxx" 00013 00014 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM 00015 00016 using namespace resip; 00017 using namespace std; 00018 00019 ServerAuthManager::ServerAuthManager(DialogUsageManager& dum, TargetCommand::Target& target) : 00020 DumFeature(dum, target) 00021 { 00022 } 00023 00024 00025 ServerAuthManager::~ServerAuthManager() 00026 { 00027 InfoLog(<< "~ServerAuthManager: " << mMessages.size() << " messages in memory when destroying."); 00028 } 00029 00030 // !bwc! We absolutely, positively, MUST NOT throw here. This is because in 00031 // DialogUsageManager::process(), we do not know if a DumFeature has taken 00032 // ownership of msg until we get a return. If we throw, the ownership of msg 00033 // is unknown. This is unacceptable. 00034 DumFeature::ProcessingResult 00035 ServerAuthManager::process(Message* msg) 00036 { 00037 SipMessage* sipMsg = dynamic_cast<SipMessage*>(msg); 00038 00039 if (sipMsg) 00040 { 00042 switch ( handle(sipMsg) ) 00043 { 00044 case ServerAuthManager::Challenged: 00045 InfoLog(<< "ServerAuth challenged request " << sipMsg->brief()); 00046 return DumFeature::ChainDoneAndEventDone; 00047 case ServerAuthManager::RequestedInfo: 00048 InfoLog(<< "ServerAuth requested info (requiresChallenge) " << sipMsg->brief()); 00049 return DumFeature::EventTaken; 00050 case ServerAuthManager::RequestedCredentials: 00051 InfoLog(<< "ServerAuth requested credentials " << sipMsg->brief()); 00052 return DumFeature::EventTaken; 00053 case ServerAuthManager::Rejected: 00054 InfoLog(<< "ServerAuth rejected request " << sipMsg->brief()); 00055 return DumFeature::ChainDoneAndEventDone; 00056 default: // includes Skipped 00057 return DumFeature::FeatureDone; 00058 } 00059 } 00060 00061 ChallengeInfo* challengeInfo = dynamic_cast<ChallengeInfo*>(msg); 00062 if(challengeInfo) 00063 { 00064 InfoLog(<< "ServerAuth got ChallengeInfo " << challengeInfo->brief()); 00065 MessageMap::iterator it = mMessages.find(challengeInfo->getTransactionId()); 00066 assert(it != mMessages.end()); 00067 std::auto_ptr<SipMessage> sipMsg(it->second); 00068 mMessages.erase(it); 00069 00070 if(challengeInfo->isFailed()) 00071 { 00072 // some kind of failure occurred while checking whether a 00073 // challenge is required 00074 InfoLog(<< "ServerAuth requiresChallenge() async failed"); 00075 SharedPtr<SipMessage> response(new SipMessage); 00076 Helper::makeResponse(*response, *sipMsg, 500, "Server Internal Error"); 00077 mDum.send(response); 00078 return DumFeature::ChainDoneAndEventDone; 00079 } 00080 00081 if(challengeInfo->isChallengeRequired()) 00082 { 00083 issueChallenge(sipMsg.get()); 00084 InfoLog(<< "ServerAuth challenged request (after async) " << sipMsg->brief()); 00085 return DumFeature::ChainDoneAndEventDone; 00086 } 00087 else 00088 { 00089 // challenge is not required, re-instate original message 00090 postCommand(auto_ptr<Message>(sipMsg)); 00091 return FeatureDoneAndEventDone; 00092 } 00093 } 00094 00095 UserAuthInfo* userAuth = dynamic_cast<UserAuthInfo*>(msg); 00096 if (userAuth) 00097 { 00098 //InfoLog(<< "Got UserAuthInfo"); 00099 UserAuthInfo* userAuth = dynamic_cast<UserAuthInfo*>(msg); 00100 if (userAuth) 00101 { 00102 Message* result = handleUserAuthInfo(userAuth); 00103 if (result) 00104 { 00105 postCommand(auto_ptr<Message>(result)); 00106 return FeatureDoneAndEventDone; 00107 } 00108 else 00109 { 00110 InfoLog(<< "ServerAuth rejected request " << *userAuth); 00111 return ChainDoneAndEventDone; 00112 } 00113 } 00114 } 00115 return FeatureDone; 00116 } 00117 00118 SipMessage* 00119 ServerAuthManager::handleUserAuthInfo(UserAuthInfo* userAuth) 00120 { 00121 assert(userAuth); 00122 00123 MessageMap::iterator it = mMessages.find(userAuth->getTransactionId()); 00124 assert(it != mMessages.end()); 00125 SipMessage* requestWithAuth = it->second; 00126 mMessages.erase(it); 00127 00128 InfoLog( << "Checking for auth result in realm=" << userAuth->getRealm() 00129 << " A1=" << userAuth->getA1()); 00130 00131 if (userAuth->getMode() == UserAuthInfo::UserUnknown || 00132 (userAuth->getMode() == UserAuthInfo::RetrievedA1 && userAuth->getA1().empty())) 00133 { 00134 InfoLog (<< "User unknown " << userAuth->getUser() << " in " << userAuth->getRealm()); 00135 SharedPtr<SipMessage> response(new SipMessage); 00136 Helper::makeResponse(*response, *requestWithAuth, 404, "User unknown."); 00137 mDum.send(response); 00138 onAuthFailure(BadCredentials, *requestWithAuth); 00139 delete requestWithAuth; 00140 return 0; 00141 } 00142 00143 if (userAuth->getMode() == UserAuthInfo::Error) 00144 { 00145 InfoLog (<< "Error in auth procedure for " << userAuth->getUser() << " in " << userAuth->getRealm()); 00146 SharedPtr<SipMessage> response(new SipMessage); 00147 Helper::makeResponse(*response, *requestWithAuth, 503, "Server Error."); 00148 mDum.send(response); 00149 onAuthFailure(Error, *requestWithAuth); 00150 delete requestWithAuth; 00151 return 0; 00152 } 00153 00154 bool stale = false; 00155 bool digestAccepted = (userAuth->getMode() == UserAuthInfo::DigestAccepted); 00156 if(userAuth->getMode() == UserAuthInfo::RetrievedA1) 00157 { 00160 std::pair<Helper::AuthResult,Data> resPair = 00161 Helper::advancedAuthenticateRequest(*requestWithAuth, 00162 userAuth->getRealm(), 00163 userAuth->getA1(), 00164 3000, 00165 proxyAuthenticationMode()); 00166 00167 switch (resPair.first) 00168 { 00169 case Helper::Authenticated: 00170 digestAccepted = true; 00171 break; 00172 case Helper::Failed: 00173 // digestAccepted = false; // already false by default 00174 break; 00175 case Helper::BadlyFormed: 00176 if(rejectBadNonces()) 00177 { 00178 InfoLog (<< "Authentication nonce badly formed for " << userAuth->getUser()); 00179 00180 SharedPtr<SipMessage> response(new SipMessage); 00181 Helper::makeResponse(*response, *requestWithAuth, 403, "Invalid nonce"); 00182 mDum.send(response); 00183 onAuthFailure(InvalidRequest, *requestWithAuth); 00184 delete requestWithAuth; 00185 return 0; 00186 } 00187 else 00188 { 00189 stale=true; 00190 } 00191 break; 00192 case Helper::Expired: 00193 stale = true; 00194 break; 00195 default: 00196 break; 00197 } 00198 } 00199 00200 if(stale || userAuth->getMode() == UserAuthInfo::Stale) 00201 { 00202 InfoLog (<< "Nonce expired for " << userAuth->getUser()); 00203 00204 issueChallenge(requestWithAuth); 00205 delete requestWithAuth; 00206 return 0; 00207 } 00208 00209 if(digestAccepted) 00210 { 00211 if (authorizedForThisIdentity(userAuth->getUser(), userAuth->getRealm(), 00212 requestWithAuth->header(h_From).uri())) 00213 { 00214 InfoLog (<< "Authorized request for " << userAuth->getRealm()); 00215 onAuthSuccess(*requestWithAuth); 00216 return requestWithAuth; 00217 } 00218 else 00219 { 00220 // !rwm! The user is trying to forge a request. Respond with a 403 00221 InfoLog (<< "User: " << userAuth->getUser() << " at realm: " << userAuth->getRealm() << 00222 " trying to forge request from: " << requestWithAuth->header(h_From).uri()); 00223 00224 SharedPtr<SipMessage> response(new SipMessage); 00225 Helper::makeResponse(*response, *requestWithAuth, 403, "Invalid user name provided"); 00226 mDum.send(response); 00227 onAuthFailure(InvalidRequest, *requestWithAuth); 00228 delete requestWithAuth; 00229 return 0; 00230 } 00231 } 00232 else 00233 { 00234 // Handles digestAccepted == false, DigestNotAccepted and any other 00235 // case that is not recognised by the foregoing logic 00236 00237 InfoLog (<< "Invalid password provided for " << userAuth->getUser() << " in " << userAuth->getRealm()); 00238 InfoLog (<< " a1 hash of password from db was " << userAuth->getA1() ); 00239 00240 SharedPtr<SipMessage> response(new SipMessage); 00241 Helper::makeResponse(*response, *requestWithAuth, 403, "Invalid password provided"); 00242 mDum.send(response); 00243 onAuthFailure(BadCredentials, *requestWithAuth); 00244 delete requestWithAuth; 00245 return 0; 00246 } 00247 } 00248 00249 00250 bool 00251 ServerAuthManager::useAuthInt() const 00252 { 00253 return false; 00254 } 00255 00256 00257 bool 00258 ServerAuthManager::proxyAuthenticationMode() const 00259 { 00260 return true; 00261 } 00262 00263 00264 bool 00265 ServerAuthManager::rejectBadNonces() const 00266 { 00267 return true; 00268 } 00269 00270 00271 ServerAuthManager::AsyncBool 00272 ServerAuthManager::requiresChallenge(const SipMessage& msg) 00273 { 00274 return True; 00275 } 00276 00277 00278 bool 00279 ServerAuthManager::authorizedForThisIdentity(const resip::Data &user, 00280 const resip::Data &realm, 00281 resip::Uri &fromUri) 00282 { 00283 // !rwm! good enough for now. TODO eventually consult a database to see what 00284 // combinations of user/realm combos are authorized for an identity 00285 00286 // First try the form where the username parameter in the auth 00287 // header is just the username component of the fromUri 00288 // 00289 if ((fromUri.user() == user) && (fromUri.host() == realm)) 00290 return true; 00291 00292 // Now try the form where the username parameter in the auth 00293 // header is the full fromUri, e.g. 00294 // Proxy-Authorization: Digest username="user@domain" ... 00295 // 00296 if ((fromUri.getAorNoPort() == user) && (fromUri.host() == realm)) 00297 return true; 00298 00299 // catch-all: access denied 00300 return false; 00301 } 00302 00303 00304 const Data& 00305 ServerAuthManager::getChallengeRealm(const SipMessage& msg) 00306 { 00307 return msg.header(h_RequestLine).uri().host(); 00308 } 00309 00310 00311 bool 00312 ServerAuthManager::isMyRealm(const Data& realm) 00313 { 00314 return mDum.isMyDomain(realm); 00315 } 00316 00317 00318 // return true if request has been consumed 00319 ServerAuthManager::Result 00320 ServerAuthManager::handle(SipMessage* sipMsg) 00321 { 00322 //InfoLog( << "trying to do auth" ); 00323 if (sipMsg->isRequest() && 00324 sipMsg->header(h_RequestLine).method() != ACK && 00325 sipMsg->header(h_RequestLine).method() != CANCEL) // Do not challenge ACKs or CANCELs 00326 { 00327 ParserContainer<Auth>* auths; 00328 if (proxyAuthenticationMode()) 00329 { 00330 if(!sipMsg->exists(h_ProxyAuthorizations)) 00331 { 00332 return issueChallengeIfRequired(sipMsg); 00333 } 00334 auths = &sipMsg->header(h_ProxyAuthorizations); 00335 } 00336 else 00337 { 00338 if(!sipMsg->exists(h_Authorizations)) 00339 { 00340 return issueChallengeIfRequired(sipMsg); 00341 } 00342 auths = &sipMsg->header(h_Authorizations); 00343 } 00344 00345 try 00346 { 00347 for(Auths::iterator it = auths->begin(); it != auths->end(); it++) 00348 { 00349 if (isMyRealm(it->param(p_realm))) 00350 { 00351 InfoLog (<< "Requesting credential for " 00352 << it->param(p_username) << " @ " << it->param(p_realm)); 00353 00354 requestCredential(it->param(p_username), 00355 it->param(p_realm), 00356 *sipMsg, 00357 *it, 00358 sipMsg->getTransactionId()); 00359 mMessages[sipMsg->getTransactionId()] = sipMsg; 00360 return RequestedCredentials; 00361 } 00362 } 00363 00364 InfoLog (<< "Didn't find matching realm "); 00365 return issueChallengeIfRequired(sipMsg); 00366 } 00367 catch(BaseException& e) 00368 { 00369 InfoLog (<< "Invalid auth header provided " << e); 00370 SharedPtr<SipMessage> response(new SipMessage); 00371 Helper::makeResponse(*response, *sipMsg, 400, "Invalid auth header"); 00372 mDum.send(response); 00373 onAuthFailure(InvalidRequest, *sipMsg); 00374 return Rejected; 00375 } 00376 } 00377 return Skipped; 00378 } 00379 00380 ServerAuthManager::Result 00381 ServerAuthManager::issueChallengeIfRequired(SipMessage *sipMsg) 00382 { 00383 // Is challenge required for this message 00384 AsyncBool required = requiresChallenge(*sipMsg); 00385 switch(required) 00386 { 00387 case False: 00388 return Skipped; 00389 case Async: 00390 mMessages[sipMsg->getTransactionId()] = sipMsg; 00391 return RequestedInfo; 00392 case True: 00393 default: 00394 issueChallenge(sipMsg); 00395 return Challenged; 00396 } 00397 } 00398 00399 void 00400 ServerAuthManager::issueChallenge(SipMessage *sipMsg) 00401 { 00402 //assume TransactionUser has matched/repaired a realm 00403 SharedPtr<SipMessage> challenge(Helper::makeChallenge(*sipMsg, 00404 getChallengeRealm(*sipMsg), 00405 useAuthInt(), 00406 false /*stale*/, 00407 proxyAuthenticationMode())); 00408 00409 InfoLog (<< "Sending challenge to " << sipMsg->brief()); 00410 mDum.send(challenge); 00411 } 00412 00413 void 00414 ServerAuthManager::onAuthSuccess(const SipMessage& msg) 00415 { 00416 // sub class may want to create a log entry 00417 } 00418 00419 void 00420 ServerAuthManager::onAuthFailure(AuthFailureReason reason, const SipMessage& msg) 00421 { 00422 // sub class may want to create a log entry 00423 } 00424 00425 00426 /* ==================================================================== 00427 * The Vovida Software License, Version 1.0 00428 * 00429 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 00430 * 00431 * Redistribution and use in source and binary forms, with or without 00432 * modification, are permitted provided that the following conditions 00433 * are met: 00434 * 00435 * 1. Redistributions of source code must retain the above copyright 00436 * notice, this list of conditions and the following disclaimer. 00437 * 00438 * 2. Redistributions in binary form must reproduce the above copyright 00439 * notice, this list of conditions and the following disclaimer in 00440 * the documentation and/or other materials provided with the 00441 * distribution. 00442 * 00443 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00444 * and "Vovida Open Communication Application Library (VOCAL)" must 00445 * not be used to endorse or promote products derived from this 00446 * software without prior written permission. For written 00447 * permission, please contact vocal@vovida.org. 00448 * 00449 * 4. Products derived from this software may not be called "VOCAL", nor 00450 * may "VOCAL" appear in their name, without prior written 00451 * permission of Vovida Networks, Inc. 00452 * 00453 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00454 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00455 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00456 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00457 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00458 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00459 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00460 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00461 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00462 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00463 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00464 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00465 * DAMAGE. 00466 * 00467 * ==================================================================== 00468 * 00469 * This software consists of voluntary contributions made by Vovida 00470 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00471 * Inc. For more information on Vovida Networks, Inc., please see 00472 * <http://www.vovida.org/>. 00473 * 00474 */
1.7.5.1