< Previous by Date Date Index Next by Date >
< Previous in Thread Thread Index  

Re: [reSIProcate] Digest credentials for many different usernames from single realm


Scott,

On Thu, 28 Sep 2006 at 09:45 -0400, Scott Godin wrote:

> I would like to see this change.

See the patch below. (I have various other local changes besides this 
patch. So, hopefully I've missed nothing.) I'll test it more 
thoroughly within several days, but I think it should work fine as is.

> I think the search order should be:
> 1.  Find a credential where both user and realm match.
> 2.  If not found, return first credential with realm match.
> 3.  If not found, return first credential with user match.
> 4.  If not found, return first credential.

If user (not auth user!) is defined for profile, and is present in 
relevant challenge header, then #1 is tried. Otherwise #2 is tried. 
(Actually #1 and #2 is the same step differentiated by operator<().) 
#3 is never tried. Although I don't like #4, it is retained for 
backward compatibility. Note that old functionality should not be 
affected by this patch.


> I think it is fairly common for proxies to get the realm stuff 
> wrong, so we need some kind of fall-back when the realm doesn't 
> match.

I don't quite understand how the proxies could get the realm stuff 
wrong taking into account that _any arbitrary_ realm string is 
allowed. What could be wrong is proxy administrator not telling the 
users this string, or users typing the wrong one, or stupid SIP-phone 
thinking proxy domain is the same thing as realm...


> I guess you are planning to match Auth user with the user in the From
> header?

Username (not auth username!) is matched against From header for 
challenges with Proxy-Authenticate header, and against To header for 
challenges with WWW-Authenticate header.


Index: resip/dum/ClientAuthManager.cxx
===================================================================
--- resip/dum/ClientAuthManager.cxx     (revision 6607)
+++ resip/dum/ClientAuthManager.cxx     (working copy)
@@ -103,7 +103,10 @@
       {    
          if (i->exists(p_realm))
          {
-            if (!mRealms[i->param(p_realm)].handleAuth(userProfile, *i, false))
+            if (!mRealms[i->param(p_realm)].handleAuth(userProfile, *i,
+                                                       challenge.exists(h_To) 
? challenge.header(h_To).uri().user()
+                                                                              
: Data::Empty,
+                                                       false))
             {
                handled = false;
                break;
@@ -122,7 +125,10 @@
       {    
          if (i->exists(p_realm))
          {
-            if (!mRealms[i->param(p_realm)].handleAuth(userProfile, *i, true))
+            if (!mRealms[i->param(p_realm)].handleAuth(userProfile, *i,
+                                                       
challenge.exists(h_From) ? challenge.header(h_From).uri().user()
+                                                                               
 : Data::Empty,
+                                                       true))
             {
                handled = false;
                break;
@@ -214,7 +220,8 @@
 }
 
 bool 
-ClientAuthManager::RealmState::handleAuth(UserProfile& userProfile, const 
Auth& auth, bool isProxyCredential)
+ClientAuthManager::RealmState::handleAuth(UserProfile& userProfile, const 
Auth& auth,
+                                          const Data& username, bool 
isProxyCredential)
 {   
    DebugLog( << "ClientAuthManager::RealmState::handleAuth: " << this << " " 
<< auth << " is proxy: " << isProxyCredential);
    mIsProxyCredential = isProxyCredential;   //this cahnging dynamically would
@@ -260,7 +267,7 @@
          return false;
    }
 
-   if (findCredential(userProfile, auth))
+   if (findCredential(userProfile, auth, username))
    {
       return true;
    }
@@ -278,7 +285,7 @@
 }
                      
 bool 
-ClientAuthManager::RealmState::findCredential(UserProfile& userProfile, const 
Auth& auth)
+ClientAuthManager::RealmState::findCredential(UserProfile& userProfile, const 
Auth& auth, const Data& username)
 {
    if (!Helper::algorithmAndQopSupported(auth))
    {
@@ -286,16 +293,15 @@
       return false;
    }
 
-   const Data& realm = auth.param(p_realm);                   
+   const Data& realm = auth.param(p_realm);
+
    //!dcm! -- icky, expose static empty soon...ptr instead of reference?
-   mCredential = userProfile.getDigestCredential(realm);
-   if ( mCredential.realm.empty() )                       
+   mCredential = userProfile.getDigestCredential(realm, username);
+   if ( mCredential.realm.empty() )
    {                                        
-      DebugLog( << "Got a 401 or 407 but could not find credentials for realm: 
" << realm);
-//      DebugLog (<< auth);
-//      DebugLog (<< response);
+      DebugLog( << "Got a 401 or 407 but could not find credentials for 
realm/username: " << realm << "/" << username);
       return false;
-   }                     
+   }
    return true;   
 }
 
@@ -312,7 +318,7 @@
    
    DebugLog( << " Add auth, " << this << " in response to: " << mAuth);
    target.push_back(Helper::makeChallengeResponseAuth(request,
-                                                      mCredential.user,
+                                                      mCredential.authuser,
                                                       mCredential.password,
                                                       mAuth, 
                                                       cnonce,
Index: resip/dum/ClientAuthManager.hxx
===================================================================
--- resip/dum/ClientAuthManager.hxx     (revision 6607)
+++ resip/dum/ClientAuthManager.hxx     (working copy)
@@ -41,7 +41,7 @@
             
             void clear();
 
-            bool handleAuth(UserProfile& userProfile, const Auth& auth, bool 
isProxyCredential);
+            bool handleAuth(UserProfile& userProfile, const Auth& auth, const 
Data& username, bool isProxyCredential);
             void authSucceeded();
 
             void addAuthentication(SipMessage& origRequest);            
@@ -57,7 +57,8 @@
 
             void transition(State s);
             static const Data& getStateString(State s);
-            bool findCredential(UserProfile& userProfile, const Auth& auth);  
+            bool findCredential(UserProfile& userProfile, const Auth& auth, 
const Data& username);
+
             UserProfile::DigestCredential mCredential;
             bool mIsProxyCredential;
             
Index: resip/dum/UserProfile.cxx
===================================================================
--- resip/dum/UserProfile.cxx   (revision 6607)
+++ resip/dum/UserProfile.cxx   (working copy)
@@ -127,11 +127,27 @@
    mDigestCredentials.clear();
 }
 
+void UserProfile::clearDigestCredential( const Data& realm, const Data& user )
+{
+   DigestCredentials::iterator it = 
mDigestCredentials.find(DigestCredential(realm, user));
+   if (it != mDigestCredentials.end())
+   {
+      DebugLog(<< "Deleting credential for realm/user: " << realm << "/" << 
user << "; " << *it);
+      mDigestCredentials.erase(it);
+   }
+}
+
 void 
-UserProfile::setDigestCredential( const Data& realm, const Data& user, const 
Data& password)
+UserProfile::setDigestCredential( const Data& realm, const Data& authuser, 
const Data& password)
 {
-   DigestCredential cred( realm, user, password );
+  setDigestCredential(realm, Data::Empty, authuser, password);
+}
 
+void 
+UserProfile::setDigestCredential( const Data& realm, const Data& user, const 
Data& authuser, const Data& password)
+{
+   DigestCredential cred(realm, user, authuser, password);
+
    DebugLog (<< "Adding credential: " << cred);
    mDigestCredentials.erase(cred);
    mDigestCredentials.insert(cred);
@@ -140,33 +156,41 @@
 const UserProfile::DigestCredential&
 UserProfile::getDigestCredential( const Data& realm  )
 {
+  return getDigestCredential( realm, Data::Empty );
+}
+
+const UserProfile::DigestCredential&
+UserProfile::getDigestCredential( const Data& realm, const Data& user )
+{
    if(mDigestCredentials.empty())
    {
-      // !jf! why not just throw here? 
+      // !jf! why not just throw here?
       static const DigestCredential empty;
       return empty;
    }
 
-   DigestCredentials::const_iterator it = 
mDigestCredentials.find(DigestCredential(realm));
+   DigestCredentials::const_iterator it = 
mDigestCredentials.find(DigestCredential(realm, user));
    if (it == mDigestCredentials.end())
    {
-      DebugLog(<< "Didn't find credential for realm: " << realm << " " << 
*mDigestCredentials.begin());
+      DebugLog(<< "Didn't find credential for realm/user: " << realm <<
+               "/" << user << "; returning " << *mDigestCredentials.begin());
       return *mDigestCredentials.begin();
    }
    else      
    {
-      DebugLog(<< "Found credential for realm: " << *it << realm);      
+      DebugLog(<< "Found credential for realm/user: " << realm << "/" << user 
<< "; " << *it);
       return *it;
    }
 }
 
-UserProfile::DigestCredential::DigestCredential(const Data& r, const Data& u, 
const Data& pwd) :
+UserProfile::DigestCredential::DigestCredential(const Data& r, const Data& u, 
const Data& au, const Data& pwd) :
    realm(r),
    user(u),
+   authuser(au),
    password(pwd)
 {  
 //    MD5Stream a1;
-//    a1 << user
+//    a1 << authuser
 //       << Symbols::COLON
 //       << realm
 //       << Symbols::COLON
@@ -177,21 +201,34 @@
 UserProfile::DigestCredential::DigestCredential() : 
    realm(Data::Empty),
    user(Data::Empty),
+   authuser(Data::Empty),
    password(Data::Empty)
 {
 }  
 
-UserProfile::DigestCredential::DigestCredential(const Data& pRealm) : 
-   realm(pRealm),
+UserProfile::DigestCredential::DigestCredential(const Data& r) : 
+   realm(r),
    user(Data::Empty),
+   authuser(Data::Empty),
    password(Data::Empty) 
 {
 }  
 
+UserProfile::DigestCredential::DigestCredential(const Data& r, const Data& u) :
+   realm(r),
+   user(u),
+   authuser(Data::Empty),
+   password(Data::Empty) 
+{
+}  
+
 bool
 UserProfile::DigestCredential::operator<(const DigestCredential& rhs) const
 {
-   return realm < rhs.realm;
+   if (user.empty() || rhs.user.empty() || realm != rhs.realm)
+      return realm < rhs.realm;
+   else
+      return user < rhs.user;
 }
 
 std::ostream&
@@ -204,7 +241,7 @@
 std::ostream&
 resip::operator<<(std::ostream& strm, const UserProfile::DigestCredential& 
cred)
 {
-   strm << "realm=" << cred.realm << " user=" << cred.user ;
+   strm << "realm=" << cred.realm << " user=" << cred.user << " authuser=" << 
cred.authuser;
    return strm;
 }
 
Index: resip/dum/UserProfile.hxx
===================================================================
--- resip/dum/UserProfile.hxx   (revision 6607)
+++ resip/dum/UserProfile.hxx   (working copy)
@@ -59,23 +59,35 @@
             DigestCredential(); 
             DigestCredential(const Data& realm, 
                              const Data& username, 
+                             const Data& authusername, 
                              const Data& pwd);
+            DigestCredential(const Data& realm, const Data& username);
             DigestCredential(const Data& realm);
                              
             Data realm;
             Data user;
+            Data authuser;
+            Data password;            
 //            Data passwordHashA1;
-            Data password;            
 
             bool operator<(const DigestCredential& rhs) const;
       };
       
       /// The following functions deal with clearing, setting and getting of 
digest credentals 
       virtual void clearDigestCredentials();
+      virtual void clearDigestCredential( const Data& realm,
+                                          const Data& user );
       virtual void setDigestCredential( const Data& realm, 
+                                        const Data& authuser, 
+                                        const Data& password);
+      virtual void setDigestCredential( const Data& realm, 
                                         const Data& user, 
+                                        const Data& authuser, 
                                         const Data& password);
       virtual const DigestCredential& getDigestCredential( const Data& realm  
);
+      virtual const DigestCredential& getDigestCredential( const Data& realm,
+                                                           const Data& 
authuser );
+
    protected:
       virtual UserProfile* clone() const;
    private:

-- 
...Bye..Dmitry.