Re: [reSIProcate] Digest credentials for many different usernames from single realm
- From: Dmitry Semyonov <dsemyonov@xxxxxxx>
- Date: Fri, 29 Sep 2006 15:07:10 +0400 (MSD)
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.