Commit e128a643 authored by Simon Morlat's avatar Simon Morlat
Browse files

Add AuthStack object to try to solve issue 5864 (double auth_info_requested()...

Add AuthStack object to try to solve issue 5864 (double auth_info_requested() because of double challenge).
Unfortunately this is not complete, as it creates problems with ProxyConfig erroneously and transciently moving to Failed state.
This will be fixed later.
parent 3ae4dd71
......@@ -552,6 +552,16 @@ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) {
sai->userid = ms_strdup(linphone_auth_info_get_userid(ai) ? linphone_auth_info_get_userid(ai) : linphone_auth_info_get_username(ai));
sai->password = linphone_auth_info_get_passwd(ai)?ms_strdup(linphone_auth_info_get_passwd(ai)) : NULL;
sai->ha1 = linphone_auth_info_get_ha1(ai) ? ms_strdup(linphone_auth_info_get_ha1(ai)) : NULL;
#if 0
AuthStack & as = L_GET_PRIVATE_FROM_C_OBJECT(lc)->getAuthStack();
if (!as.empty()){
/* We have to construct the auth info as it was originally requested in auth_requested() below,
* so that the matching is made correctly.
*/
as.authFound(AuthInfo::create(sai->username, "", "", "", sai->realm, sai->domain));
}
#endif
} else if (sai->mode == SalAuthModeTls) {
if (linphone_auth_info_get_tls_cert(ai) && linphone_auth_info_get_tls_key(ai)) {
sal_certificates_chain_parse(sai, linphone_auth_info_get_tls_cert(ai), SAL_CERTIFICATE_RAW_FORMAT_PEM);
......@@ -585,10 +595,19 @@ static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) {
} else {
LinphoneAuthMethod method = sai->mode == SalAuthModeHttpDigest ? LinphoneAuthHttpDigest : LinphoneAuthTls;
LinphoneAuthInfo *ai = linphone_core_create_auth_info(lc, sai->username, NULL, NULL, NULL, sai->realm, sai->domain);
linphone_core_notify_authentication_requested(lc, ai, method);
#if 0
if (method == LinphoneAuthHttpDigest){
/* Request app for new authentication information, but later. */
L_GET_PRIVATE_FROM_C_OBJECT(lc)->getAuthStack().pushAuthRequested(AuthInfo::toCpp(ai)->getSharedFromThis());
}else
#endif
{
linphone_core_notify_authentication_requested(lc, ai, method);
// Deprecated callback
linphone_core_notify_auth_info_requested(lc, sai->realm, sai->username, sai->domain);
}
linphone_auth_info_unref(ai);
// Deprecated
linphone_core_notify_auth_info_requested(lc, sai->realm, sai->username, sai->domain);
if (fill_auth_info(lc, sai)) {
return TRUE;
}
......
......@@ -99,6 +99,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
address/identity-address.h
address/identity-address-parser.h
auth-info/auth-info.h
auth-info/auth-stack.h
c-wrapper/c-wrapper.h
c-wrapper/internal/c-sal.h
c-wrapper/internal/c-tools.h
......@@ -293,6 +294,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
c-wrapper/internal/c-sal.cpp
c-wrapper/internal/c-tools.cpp
auth-info/auth-info.cpp
auth-info/auth-stack.cpp
call/call.cpp
call/local-conference-call.cpp
call/remote-conference-call.cpp
......
......@@ -60,6 +60,8 @@ class AuthInfo : public bellesip::HybridObject<LinphoneAuthInfo, AuthInfo> {
const std::string& getTlsKey() const;
const std::string& getTlsCertPath() const;
const std::string& getTlsKeyPath() const;
std::string toString() const override;
private:
std::string mUsername;
......@@ -74,7 +76,7 @@ class AuthInfo : public bellesip::HybridObject<LinphoneAuthInfo, AuthInfo> {
std::string mTlsCertPath;
std::string mTlsKeyPath;
std::string toString() const override;
};
......
/*
* Copyright (c) 2010-2019 Belledonne Communications SARL.
*
* This file is part of Liblinphone.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "auth-stack.h"
#include "core/core-p.h"
#include "private_functions.h"
using namespace::std;
LINPHONE_BEGIN_NAMESPACE
AuthStack::AuthStack(CorePrivate & core) : mCore(core){
}
AuthStack::~AuthStack(){
if (mTimer){
mCore.getSal()->cancelTimer(mTimer);
belle_sip_object_unref(mTimer);
mTimer = nullptr;
}
}
void AuthStack::pushAuthRequested(const std::shared_ptr<AuthInfo> &ai){
if (mAuthBeingRequested) return;
lInfo() << "AuthRequested pushed";
mAuthQueue.push_back(ai);
if (!mTimer){
mTimer = mCore.getSal()->createTimer(&onTimeout, this, 0, "authentication requests");
}
}
void AuthStack::authFound(const std::shared_ptr<AuthInfo> &ai){
if (mAuthBeingRequested) return;
lInfo() << "AuthStack::authFound() for " << ai->toString();
for(auto it = mAuthQueue.begin(); it != mAuthQueue.end(); ){
const shared_ptr<AuthInfo> &authInfo = (*it);
if (authInfo->getRealm() == ai->getRealm() &&
authInfo->getUsername() == ai->getUsername() &&
authInfo->getDomain() == ai->getDomain()){
lInfo() << "Authentication request removed.";
it = mAuthQueue.erase(it);
}else ++it;
}
if (mAuthQueue.empty()){
lInfo() << "No need to request authentication information from application.";
if (mTimer){
mCore.getSal()->cancelTimer(mTimer);
belle_sip_object_unref(mTimer);
mTimer = nullptr;
}
}
}
void AuthStack::processAuthRequested(){
/* The auth_info_requested() callback may cause the application to directly call linphone_core_add_auth_info(), which
* will re-invoke the auth_requsted callback of the SAL, which may call authFound() here.
* The mAuthBeingRequested flag is to inhinit this behavior.
*/
mAuthBeingRequested = true;
for(const auto &authInfo : mAuthQueue){
linphone_core_notify_authentication_requested(mCore.getCCore(), authInfo->toC(), LinphoneAuthHttpDigest);
// Deprecated callback:
linphone_core_notify_auth_info_requested(mCore.getCCore(), authInfo->getRealm().c_str(), authInfo->getUsername().c_str(), authInfo->getDomain().c_str());
}
mAuthQueue.clear();
belle_sip_object_unref(mTimer);
mTimer = nullptr;
mAuthBeingRequested = false;
}
int AuthStack::onTimeout(void *data, unsigned int events){
AuthStack *zis = static_cast<AuthStack*>(data);
zis->processAuthRequested();
return BELLE_SIP_STOP;
}
LINPHONE_END_NAMESPACE
/*
* Copyright (c) 2010-2019 Belledonne Communications SARL.
*
* This file is part of Liblinphone.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef AUTH_STACK_H
#define AUTH_STACK_H
#include "linphone/api/c-types.h"
#include "auth-info.h"
typedef struct belle_sip_source belle_sip_source_t;
LINPHONE_BEGIN_NAMESPACE
class CorePrivate;
/*
* Help object to request authentication information to the app.
* It solves the following problem:
* Belle-sip requests authentication information sequentially by iterating on challenges
* However, there might be for a same proxy, a challenge with SHA256 and another one with MD5, for the same user account.
* Now let's imagine the core has been provisionned with a SHA256 password but MD5 is proposed first bby the server.
* LinphoneCore will requests the app (in auth_info_requested() callback) the app for password (for MD5), while
* it has a SHA256 authentication information.
* This is annoying. This class solves the problem by deferring the auth_info_Requested() calls outside of the
* belle-sip iteration on challenges.
*/
class AuthStack{
public:
AuthStack(CorePrivate &core);
AuthStack(const AuthStack &ref) = delete;
void pushAuthRequested(const std::shared_ptr<AuthInfo> &ai);
void authFound(const std::shared_ptr<AuthInfo> &ai);
bool empty()const{
return mAuthQueue.empty();
}
~AuthStack();
private:
void processAuthRequested();
CorePrivate &mCore;
belle_sip_source_t *mTimer = nullptr;
std::list<std::shared_ptr<AuthInfo>> mAuthQueue;
bool mAuthBeingRequested = false;
static int onTimeout(void *data, unsigned int events);
};
LINPHONE_END_NAMESPACE
#endif
......@@ -27,6 +27,7 @@
#include "db/main-db.h"
#include "object/object-p.h"
#include "sal/call-op.h"
#include "auth-info/auth-stack.h"
// =============================================================================
......@@ -44,7 +45,7 @@ public:
DatabaseConnectionFailure(const char *what) : std::runtime_error(what) {}
DatabaseConnectionFailure(const std::string &what) : std::runtime_error(what) {}
};
CorePrivate();
void init ();
void registerListener (CoreListener *listener);
void unregisterListener (CoreListener *listener);
......@@ -122,6 +123,11 @@ public:
std::unique_ptr<RemoteConferenceListEventHandler> remoteListEventHandler;
std::unique_ptr<LocalConferenceListEventHandler> localListEventHandler;
#endif
AuthStack &getAuthStack(){
return authStack;
}
Sal * getSal();
LinphoneCore *getCCore();
private:
bool isInBackground = false;
......@@ -141,6 +147,7 @@ private:
// This is to keep a ref on a clientGroupChatRoom while it is being created
// Otherwise the chatRoom will be freed() before it is inserted
std::unordered_map<const AbstractChatRoom *, std::shared_ptr<const AbstractChatRoom>> noCreatedClientGroupChatRooms;
AuthStack authStack;
L_DECLARE_PUBLIC(Core);
};
......
......@@ -194,6 +194,14 @@ belle_sip_main_loop_t *CorePrivate::getMainLoop(){
return belle_sip_stack_get_main_loop(static_cast<belle_sip_stack_t*>(q->getCCore()->sal->getStackImpl()));
}
Sal * CorePrivate::getSal(){
return getPublic()->getCCore()->sal;
}
LinphoneCore *CorePrivate::getCCore(){
return getPublic()->getCCore();
}
void CorePrivate::doLater(const std::function<void ()> &something){
belle_sip_main_loop_cpp_do_later(getMainLoop(), something);
}
......@@ -214,6 +222,9 @@ bool CorePrivate::basicToFlexisipChatroomMigrationEnabled()const{
return linphone_config_get_bool(linphone_core_get_config(q->getCCore()), "misc", "enable_basic_to_client_group_chat_room_migration", FALSE);
}
CorePrivate::CorePrivate() : authStack(*this){
}
// =============================================================================
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment