13#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
22 mIsProxyCredential(isProxyCredential), mAuth(auth), mCredential(credential), mAuthQop(authQop), mNonceCountString(nonceCountString) {}
26 const Tuple &destination,
27 const Data& sigcompId)
31 Auths & target = mIsProxyCredential ? msg.
header(h_ProxyAuthorizations) : msg.
header(h_Authorizations);
33 DebugLog( <<
" Add auth in response to: " << mAuth);
37 DebugLog(<<
"Using extension to make auth response");
89 DebugLog(<<
"ClientAuthDecorator, proxy: " << mIsProxyCredential <<
" " << target.
back());
93 Auths & target = mIsProxyCredential ? msg.
header(h_ProxyAuthorizations) : msg.
header(h_Authorizations);
98 bool mIsProxyCredential;
102 Data mNonceCountString;
121 if (code < 101 || code >= 500)
125 else if (!(code == 401 || code == 407))
127 AttemptedAuthMap::iterator it = mAttemptedAuths.find(
id);
128 if (it != mAttemptedAuths.end())
130 DebugLog(<<
"ClientAuthManager::handle: transitioning " <<
id <<
"to cached");
133 it->second.authSucceeded();
139 if (!(response.
exists(h_WWWAuthenticates) || response.
exists(h_ProxyAuthenticates)))
141 DebugLog(<<
"Invalid challenge for " <<
id <<
", nothing to respond to; fail");
145 AuthState& authState = mAttemptedAuths[id];
149 if (authState.handleChallenge(userProfile, response))
152 origRequest.
header(h_CSeq).sequence()++;
153 DebugLog(<<
"Produced response to digest challenge for " << userProfile);
164 ErrLog(<<
"Unexpected exception in ClientAuthManager::handle " << e);
172 AttemptedAuthMap::iterator it = mAttemptedAuths.find(
DialogSetId(request));
173 if (it != mAttemptedAuths.end())
175 it->second.addAuthentication(request);
182 AttemptedAuthMap::iterator it = mAttemptedAuths.find(dsId);
183 if (it != mAttemptedAuths.end())
185 mAttemptedAuths.erase(it);
190ClientAuthManager::dialogSetDestroyed(
const DialogSetId&
id)
195ClientAuthManager::AuthState::AuthState() :
211 bool handled =
false;
212 if (challenge.
exists(h_WWWAuthenticates))
214 handled = handleChallenge(userProfile, challenge.
header(h_WWWAuthenticates),
false );
216 if (!handled && challenge.
exists(h_ProxyAuthenticates))
218 handled = handleChallenge(userProfile, challenge.
header(h_ProxyAuthenticates),
true );
223 InfoLog(<<
"ClientAuthManager::AuthState::handleChallenge failed for: " << challenge);
233ClientAuthManager::AuthState::handleChallenge(
UserProfile& userProfile,
const Auths& auths,
bool isProxyCredential)
238 if (i->exists(p_realm))
240 if (mRealms[i->param(p_realm)].handleAuth(userProfile, *i, isProxyCredential))
254 if (i->exists(p_realm))
256 mRealms[i->param(p_realm)].transitionToFailedIfInitial();
264ClientAuthManager::AuthState::authSucceeded()
266 for(RealmStates::iterator i = mRealms.begin(); i!=mRealms.end(); i++)
268 i->second.authSucceeded();
271 if(mCacheUseLimit != 0 && mCacheUseCount >= mCacheUseLimit)
280ClientAuthManager::AuthState::addAuthentication(
SipMessage& request)
282 request.
remove(h_ProxyAuthorizations);
283 request.
remove(h_Authorizations);
287 for(RealmStates::iterator i = mRealms.begin(); i!=mRealms.end(); i++)
289 i->second.addAuthentication(request);
293ClientAuthManager::RealmState::RealmState() :
294 mIsProxyCredential(false),
310ClientAuthManager::RealmState::getStateString(
State s)
316ClientAuthManager::RealmState::transition(
State s)
318 DebugLog(<<
"ClientAuthManager::RealmState::transition from " << getStateString(mState) <<
" to " << getStateString(s));
323ClientAuthManager::RealmState::authSucceeded()
342ClientAuthManager::RealmState::handleAuth(
UserProfile& userProfile,
const Auth& auth,
bool isProxyCredential)
344 DebugLog(<<
"ClientAuthManager::RealmState::handleAuth: " <<
this <<
" " << auth <<
" is proxy: " << isProxyCredential);
345 mIsProxyCredential = isProxyCredential;
352 if (auth.
exists(p_stale) && auth.
param(p_stale) ==
"true")
354 DebugLog(<<
"Stale nonce:" << auth);
358 else if (auth.
exists(p_nonce) && auth.
param(p_nonce) != mAuth.param(p_nonce))
360 DebugLog(<<
"Different nonce, was: " << mAuth.param(p_nonce) <<
" now " << auth.
param(p_nonce));
367 DebugLog(<<
"Challenge response already failed for: " << auth);
373 DebugLog(<<
"Extra chance still failed: " << auth);
386 if (findCredential(userProfile, auth))
390 if (mState == Initial)
400 if (mState != Initial)
409ClientAuthManager::RealmState::clear()
415ClientAuthManager::RealmState::findCredential(
UserProfile& userProfile,
const Auth& auth)
421 DebugLog(<<
"Unsupported algorithm or qop: " << auth);
429 if (mCredential.realm.empty())
431 DebugLog(<<
"Got a 401 or 407 but could not find credentials for realm: " << realm);
438 if (mCredential.isPasswordA1Hash)
450ClientAuthManager::RealmState::addAuthentication(
SipMessage& request)
453 if (mState == Failed)
return;
455 Data nonceCountString;
464 std::unique_ptr<MessageDecorator> clientAuthDecorator(
new ClientAuthDecorator(mIsProxyCredential, mAuth, mCredential, authQop, nonceCountString));
469ClientAuthManager::RealmState::transitionToFailedIfInitial()
471 if (mState == Initial)
#define resip_assert(x)
This file needs to work for both C and C++ code.
ClientAuthDecorator(bool isProxyCredential, const Auth &auth, const UserProfile::DigestCredential &credential, const Data &authQop, const Data &nonceCountString)
virtual MessageDecorator * clone() const
virtual void rollbackMessage(SipMessage &msg)
virtual ~ClientAuthDecorator()
virtual void decorateMessage(SipMessage &msg, const Tuple &source, const Tuple &destination, const Data &sigcompId)
Represents the "credentials" and "challenge" elements in the SIP grammar.
bool exists(const Param< Auth > ¶mType) const
const Data & param(const ExtensionParameter ¶m) const
Const accessor for non-natively-supported parameter types.
The abstract base-class for all exceptions thrown by resip code.
static ClientAuthExtension & instance()
virtual void makeChallengeResponseAuthWithA1(const SipMessage &request, const Data &username, const Data &passwordHashA1, const Auth &challenge, const Data &cnonce, const Data &authQop, const Data &nonceCountString, Auth &auth)
virtual void makeChallengeResponseAuth(const SipMessage &request, const Data &username, const Data &password, const Auth &challenge, const Data &cnonce, const Data &authQop, const Data &nonceCountString, Auth &auth)
virtual bool handle(UserProfile &userProfile, SipMessage &origRequest, const SipMessage &response)
virtual void addAuthentication(SipMessage &origRequest)
virtual void clearAuthenticationState(const DialogSetId &dsId)
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
bool empty() const noexcept
Checks whether the Data is empty.
static const Data & getDigestName(DigestType digestType)
static Auth makeChallengeResponseAuthWithA1(const SipMessage &request, const Data &username, const Data &resipPasswordHashA1, const Auth &challenge, const Data &cnonce, unsigned int &nonceCount, Data &nonceCountString)
static void updateNonceCount(unsigned int &nonceCount, Data &nonceCountString)
static bool algorithmAndQopSupported(const Auth &challenge)
static Data qopOption(const Auth &challenge)
static bool isDigestTypeSupportedInResipA1HashString(const Data &resipA1HashString, DigestType digestType)
static Auth makeChallengeResponseAuth(const SipMessage &request, const Data &username, const Data &password, const Auth &challenge, const Data &cnonce, unsigned int &nonceCount, Data &nonceCountString)
void pop_back()
if mParsers vector is not empty, erase the first element
A const_iterator class (bidirectional)
Container class for ParserCategory, used by SipMessage to represent multi-valued headers (Contact,...
iterator end()
Returns an iterator pointing to the last header field value.
T & back()
Returns the last header field value in this container.
iterator begin()
Returns an iterator pointing to the first header field value.
void push_back(const T &t)
Inserts a header field value at the back of this container.
static Data getCryptoRandomHex(unsigned int numBytes)
Represents a SIP message.
bool isRequest() const
Returns true if message is a request, false otherwise.
void addOutboundDecorator(std::unique_ptr< MessageDecorator > md)
Call a MessageDecorator to process the message before it is sent to the transport.
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
bool isResponse() const
Returns true if message is a response, false otherwise.
bool exists(const HeaderBase &headerType) const
Returns true if the given header field is present, false otherwise.
void remove(const HeaderBase &headerType)
Prevents a header field from being present when the message is prepared for sending to a transport.
Represents a network address.
virtual const DigestCredential & getDigestCredential(const Data &realm)
virtual unsigned long getDigestCacheUseLimit() const noexcept
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine