Commit 8df16ca4 authored by François Grisez's avatar François Grisez

[module::Authentication] adapt the digest algorithm of the Authentication...

[module::Authentication] adapt the digest algorithm of the Authentication header according to the algorithm used in the user database
parent b1b60da8
Pipeline #8162 passed with stages
in 36 minutes and 50 seconds
......@@ -42,7 +42,6 @@ option(ENABLE_STRICT "Pass strict flags to the compiler" YES)
option(ENABLE_DATEHANDLER "Build DateHandler module" NO)
option(ENABLE_PDFDOC "Build pdf documentation" NO)
option(ENABLE_MONOTONIC_CLOCK_REGISTRATIONS "Enable monotonic clock for registrations" NO)
option(ENABLE_ODBC "Build ODBC support for database connection" NO)
option(ENABLE_PRESENCE "Build presence support" NO)
option(ENABLE_CONFERENCE "Build conference support" NO)
option(ENABLE_PROTOBUF "Build with protobuf support" NO)
......@@ -120,30 +119,6 @@ if(ENABLE_SNMP)
execute_process(COMMAND "${NET_SNMP_PROG}" "--agent-libs" OUTPUT_VARIABLE NET_SNMP_LIBRARIES OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
if(ENABLE_ODBC)
FIND_PROGRAM_REQUIRED(ODBC_PROG odbc_config)
execute_process(COMMAND "${ODBC_PROG}" "--libs" OUTPUT_VARIABLE ODBC_LIBRARIES OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND "${ODBC_PROG}" "--cflags" OUTPUT_VARIABLE ODBC_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND "${ODBC_PROG}" "--include-prefix" OUTPUT_VARIABLE ODBC_INCLUDE_DIRS OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND "${ODBC_PROG}" "--lib-prefix" OUTPUT_VARIABLE ODBC_LIBRARY_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "ODBC libraries: ${ODBC_LIBRARIES}")
message(STATUS "ODBC headers: ${ODBC_CFLAGS}")
# check SQL headers
find_path(ODBC_SQL_HEADERS NAMES sql.h sqlext.h sqltypes.h mysql/mysql.h PATHS ODBC_INCLUDE_DIRS)
if(NOT ODBC_SQL_HEADERS)
message(FATAL_ERROR "ODBC Mysql headers not found.")
else()
message(STATUS "ODBC Mysql ${ODBC_SQL_HEADERS}")
endif()
# check that odbc_config gives us a correct library path
find_library(ODBC_LIB_FOUND NAMES odbc PATHS ODBC_LIBRARY_DIR)
if(NOT ODBC_LIB_FOUND)
message(FATAL_ERROR "ODBC library not found.")
endif()
endif()
if(ENABLE_TRANSCODER)
find_package(Mediastreamer2 2.9.0 REQUIRED)
endif()
......
......@@ -46,8 +46,7 @@ public:
bool doOnConfigStateChanged(const ConfigValue &conf, ConfigState state) override;
private:
FlexisipAuthModuleBase *createAuthModule(const std::string &domain, const std::string &algorithm) override;
FlexisipAuthModuleBase *createAuthModule(const std::string &domain, const std::string &algorithm, int nonceExpire) override;
FlexisipAuthModuleBase *createAuthModule(const std::string &domain, int nonceExpire, bool qopAuth) override;
void validateRequest(const std::shared_ptr<RequestSipEvent> &request) override;
void processAuthentication(const std::shared_ptr<RequestSipEvent> &request, FlexisipAuthModuleBase &am) override;
......
......@@ -104,6 +104,7 @@ set(FLEXISIP_SOURCES
telephone-event-filter.cc
transaction.cc
uac-register.cc
utils/digest.cc utils/digest.hh
utils/sip-uri.cc
utils/string-formater.cc
utils/string-utils.cc
......@@ -133,13 +134,6 @@ if(ENABLE_SNMP)
list(APPEND FLEXISIP_INCLUDES ${NET_SNMP_INCLUDE_DIRS} ${CMAKE_CURRENT_LIST_DIR}/mib)
endif()
if(ENABLE_ODBC)
add_definitions(-DENABLE_ODBC)
list(APPEND FLEXISIP_SOURCES authdb-odbc.cc)
list(APPEND FLEXISIP_LIBS ${ODBC_LIBRARIES})
list(APPEND FLEXISIP_INCLUDES ${ODBC_INCLUDE_DIRS})
endif()
if(ENABLE_TRANSCODER)
list(APPEND FLEXISIP_SOURCES callcontext-transcoder.cc callcontext-transcoder.hh)
list(APPEND FLEXISIP_LIBS ${MEDIASTREAMER2_LIBRARIES})
......
......@@ -31,30 +31,18 @@ using namespace flexisip;
// FlexisipAuthModuleBase class
// ====================================================================================================================
FlexisipAuthModuleBase::FlexisipAuthModuleBase(su_root_t *root, const std::string &domain, const std::string &algo):
FlexisipAuthModuleBase::FlexisipAuthModuleBase(su_root_t *root, const std::string &domain, int nonceExpire, bool qopAuth):
AuthModule(root,
AUTHTAG_REALM(domain.c_str()),
AUTHTAG_OPAQUE("+GNywA=="),
AUTHTAG_FORBIDDEN(1),
AUTHTAG_ALLOW("ACK CANCEL BYE"),
AUTHTAG_ALGORITHM(algo.c_str()),
TAG_END()
),
mDisableQOPAuth(true) {
}
FlexisipAuthModuleBase::FlexisipAuthModuleBase(su_root_t *root, const std::string &domain, const std::string &algo, int nonceExpire):
AuthModule(root,
AUTHTAG_REALM(domain.c_str()),
AUTHTAG_OPAQUE("+GNywA=="),
AUTHTAG_QOP("auth"),
AUTHTAG_FORBIDDEN(1),
AUTHTAG_ALLOW("ACK CANCEL BYE"),
AUTHTAG_ALGORITHM(algo.c_str()),
AUTHTAG_EXPIRES(nonceExpire),
AUTHTAG_NEXT_EXPIRES(nonceExpire),
AUTHTAG_QOP(qopAuth ? "auth" : nullptr),
TAG_END()
) {
),
mQOPAuth(qopAuth) {
mNonceStore.setNonceExpires(nonceExpire);
}
......@@ -101,41 +89,43 @@ void FlexisipAuthModuleBase::onCheck(AuthStatus &as, msg_auth_t *au, auth_challe
/* There was no realm or credentials, send challenge */
SLOGD << __func__ << ": no credentials matched realm or no realm";
challenge(as, ach);
mNonceStore.insert(as.response());
// Retrieve the password in the hope it will be in cache when the remote UAC
// sends back its request; this time with the expected authentication credentials.
if (mImmediateRetrievePass) {
loadPassword(authStatus);
}
finish(authStatus);
return;
}
}
void FlexisipAuthModuleBase::onChallenge(AuthStatus &as, auth_challenger_t const *ach) {
auto &flexisipAs = dynamic_cast<FlexisipAuthStatus &>(as);
auth_challenge_digest(mAm, as.getPtr(), ach);
msg_header_t *response = as.response();
as.response(nullptr);
auto &flexisipAs = dynamic_cast<FlexisipAuthStatus &>(as);
msg_header_t *lastChallenge = nullptr;
for (const std::string &algo : flexisipAs.usedAlgo()) {
msg_header_t *challenge;
const char *algoValue = msg_header_find_param(reinterpret_cast<msg_common_t *>(response), "algorithm");
const char *algoValue = msg_header_find_param(response->sh_common, "algorithm");
if (algo == &algoValue[1]) {
challenge = response;
} else {
const char *param = su_sprintf(as.home(), "algorithm=%s", algo.c_str());
challenge = msg_header_copy(as.home(), response);
msg_header_replace_param(as.home(), reinterpret_cast<msg_common_t *>(challenge), param);
msg_header_replace_param(as.home(), challenge->sh_common, param);
}
if (as.response()) {
reinterpret_cast<msg_auth_t *>(as.response())->au_next = reinterpret_cast<msg_auth_t *>(challenge);
} else {
if (lastChallenge == nullptr) {
as.response(challenge);
} else {
lastChallenge->sh_auth->au_next = challenge->sh_auth;
}
lastChallenge = challenge;
}
if (as.response() == nullptr) {
as.status(500);
as.phrase("Internal error");
} else {
mNonceStore.insert(as.response()->sh_auth);
}
}
......
......@@ -44,19 +44,19 @@ public:
* @brief Instantiate a new authentication module without QOP authentication feature.
* @param[in] root Event loop which the module will be working on.
* @param[in] domain The domain name which the module is in charge of.
* @param[in] algo The digest algorithm to use. Only "MD5" and "SHA-256" are supported.
*/
FlexisipAuthModuleBase(su_root_t *root, const std::string &domain, const std::string &algo);
/**
* @brief Instantiate a new authentication module with QOP authentication feature enabled.
* @param[in] nonceExpire Validity period for a nonce in seconds.
* @param[in] qopAuth Setting true allows clients to use the same nonce for successive authentication.
*/
FlexisipAuthModuleBase(su_root_t *root, const std::string &domain, const std::string &algo, int nonceExpire);
FlexisipAuthModuleBase(su_root_t *root, const std::string &domain, int nonceExpire, bool qopAuth);
~FlexisipAuthModuleBase() override = default;
NonceStore &nonceStore() {return mNonceStore;}
protected:
void onCheck(AuthStatus &as, msg_auth_t *credentials, auth_challenger_t const *ach) override;
void onChallenge(AuthStatus &as, auth_challenger_t const *ach) override;
void onCancel(AuthStatus &as) override;
/**
* This method is called each time the module want to authenticate an Authorization header.
* The result of the authentication must be store in 'status' attribute of 'as' parameter as
......@@ -66,24 +66,12 @@ protected:
* @param[in] credentials The authorization header to validate.
*/
virtual void checkAuthHeader(FlexisipAuthStatus &as, msg_auth_t *credentials, auth_challenger_t const *ach) = 0;
/**
* This function is called when the module is validating a request that doesn't have any authorization header.
* It allows implementations based on password database to load the password in cache in order to be already fetched
* once the user send a request containing the Authorization header. The default implementation of this method does nothing.
*/
virtual void loadPassword(const FlexisipAuthStatus &as) = 0;
void finish(FlexisipAuthStatus &as);
void onError(FlexisipAuthStatus &as);
NonceStore mNonceStore;
bool mDisableQOPAuth = false;
bool mImmediateRetrievePass = true;
private:
void onCheck(AuthStatus &as, msg_auth_t *credentials, auth_challenger_t const *ach) override;
void onChallenge(AuthStatus &as, auth_challenger_t const *ach) override;
void onCancel(AuthStatus &as) override;
bool mQOPAuth = false;
};
}
\ No newline at end of file
}
This diff is collapsed.
......@@ -27,10 +27,12 @@
#include <sofia-sip/su_wait.h>
#include <flexisip/auth-module.hh>
#include "authdb.hh"
#include "flexisip-auth-module-base.hh"
#include "flexisip-auth-status.hh"
#include "nonce-store.hh"
#include "utils/digest.hh"
namespace flexisip {
......@@ -41,55 +43,41 @@ class FlexisipAuthModule : public FlexisipAuthModuleBase {
public:
using PasswordFetchResultCb = std::function<void(bool)>;
FlexisipAuthModule(su_root_t *root, const std::string &domain, const std::string &algo): FlexisipAuthModuleBase(root, domain, algo) {}
FlexisipAuthModule(su_root_t *root, const std::string &domain, const std::string &algo, int nonceExpire): FlexisipAuthModuleBase(root, domain, algo, nonceExpire) {}
FlexisipAuthModule(su_root_t *root, const std::string &domain, int nonceExpire, bool qopAuth): FlexisipAuthModuleBase(root, domain, nonceExpire, qopAuth) {}
~FlexisipAuthModule() override = default;
void setOnPasswordFetchResultCb(const PasswordFetchResultCb &cb) {mPassworFetchResultCb = cb;}
private:
class AuthenticationListener : public AuthDbListener {
class GenericAuthListener : public AuthDbListener {
public:
AuthenticationListener(FlexisipAuthModule &am, FlexisipAuthStatus &as, const auth_challenger_t &ach, const auth_response_t &ar): mAm(am), mAs(as), mAch(ach), mAr(ar) {}
~AuthenticationListener() override = default;
FlexisipAuthStatus &authStatus() const {return mAs;}
const auth_challenger_t &challenger() const {return mAch;}
auth_response_t *response() {return &mAr;}
std::string password() const {return mPassword;}
AuthDbResult result() const {return mResult;}
GenericAuthListener(su_root_t *root, const AuthDbBackend::ResultCb &func): mRoot(root), mFunc(func) {}
GenericAuthListener(const GenericAuthListener &) = default;
void onResult(AuthDbResult result, const std::string &passwd) override;
void onResult(AuthDbResult result, const std::vector<passwd_algo_t> &passwd) override;
void finishVerifyAlgos(const std::vector<passwd_algo_t> &pass) override;
void onResult(AuthDbResult result, const AuthDbBackend::PwList &passwd) override;
private:
static void main_thread_async_response_cb(su_root_magic_t *rm, su_msg_r msg, void *u);
friend class Authentication;
FlexisipAuthModule &mAm;
FlexisipAuthStatus &mAs;
const auth_challenger_t &mAch;
auth_response_t mAr;
AuthDbResult mResult;
std::string mPassword;
static void main_thread_async_response_cb(su_root_magic_t *rm, su_msg_r msg, void *u) noexcept;
su_root_t *mRoot = nullptr;
AuthDbBackend::ResultCb mFunc;
AuthDbResult mResult = PENDING;
AuthDbBackend::PwList mPasswords;
};
void onChallenge(AuthStatus &as, auth_challenger_t const *ach) override;
void returnChallenge(FlexisipAuthStatus &as, const auth_challenger_t &ach);
void checkAuthHeader(FlexisipAuthStatus &as, msg_auth_t *credentials, auth_challenger_t const *ach) override;
void loadPassword(const FlexisipAuthStatus &as) override;
void processResponse(AuthenticationListener &listener);
void checkPassword(FlexisipAuthStatus &as, const auth_challenger_t &ach, auth_response_t &ar, const char *password);
int checkPasswordForAlgorithm(FlexisipAuthStatus &as, auth_response_t &ar, const char *password);
int checkPasswordMd5(FlexisipAuthStatus &as, auth_response_t &ar, const char *passwd);
static std::string auth_digest_a1_for_algorithm(const auth_response_t *ar, const std::string &secret);
static std::string auth_digest_a1sess_for_algorithm(const auth_response_t *ar, const std::string &ha1);
static std::string auth_digest_response_for_algorithm(::auth_response_t *ar, char const *method_name, void const *data, isize_t dlen, const std::string &ha1);
static std::string sha256(const std::string &data);
static std::string sha256(const void *data, size_t len);
static std::string toString(const std::vector<uint8_t> &data);
void processResponse(FlexisipAuthStatus &as, const auth_response_t &ar, const auth_challenger_t &ach, AuthDbResult result, const AuthDbBackend::PwList &passwords);
void checkPassword(FlexisipAuthStatus &as, const auth_challenger_t &ach, const auth_response_t &ar, const std::string &password);
int checkPasswordForAlgorithm(FlexisipAuthStatus &as, const auth_response_t &ar, const std::string &password);
static std::string auth_digest_a1_for_algorithm(Digest &algo, const auth_response_t &ar, const std::string &secret);
static std::string auth_digest_a1sess_for_algorithm(Digest &algo, const auth_response_t &ar, const std::string &ha1);
static std::string auth_digest_response_for_algorithm(Digest &algo, const ::auth_response_t &ar, const std::string &method_name, const void *body, size_t bodyLen, const std::string &ha1);
PasswordFetchResultCb mPassworFetchResultCb;
};
......
......@@ -38,8 +38,8 @@ int NonceStore::getNc(const string &nonce) {
return -1;
}
void NonceStore::insert(msg_header_t *response) {
const char *nonce = msg_header_find_param((msg_common_t const *)response, "nonce");
void NonceStore::insert(const msg_auth_t *response) {
const char *nonce = msg_header_find_param(response->au_common, "nonce");
string snonce(nonce);
snonce = snonce.substr(1, snonce.length() - 2);
LOGD("New nonce %s", snonce.c_str());
......
......@@ -31,7 +31,7 @@ class NonceStore {
public:
void setNonceExpires(int value) {mNonceExpires = value;}
int getNc(const std::string &nonce);
void insert(msg_header_t *response);
void insert(const msg_auth_t *response);
void insert(const std::string &nonce);
void updateNc(const std::string &nonce, int newnc);
void erase(const std::string &nonce);
......@@ -50,4 +50,4 @@ private:
int mNonceExpires = 3600;
};
}
\ No newline at end of file
}
......@@ -16,23 +16,24 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define SU_MSG_ARG_T struct auth_splugin_t
#include <fstream>
#include <iostream>
#include <sstream>
#include <belr/abnf.h>
#include <belr/grammarbuilder.h>
#ifdef HAVE_CONFIG_H
#include "flexisip-config.h"
#endif
#include "authdb.hh"
#include "belr/grammarbuilder.h"
#include "belr/abnf.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include "utils/digest.hh"
using namespace::belr;
using namespace std;
using namespace flexisip;
namespace flexisip {
void FileAuthDb::parsePasswd(const vector<passwd_algo_t> &srcPasswords, const string &user, const string &domain, vector<passwd_algo_t> &destPasswords) {
// Creates pass-md5, pass-sha256 if there is clrtxt pass
......@@ -46,11 +47,11 @@ void FileAuthDb::parsePasswd(const vector<passwd_algo_t> &srcPasswords, const st
string input;
input = user+":"+domain+":"+clrtxt.pass;
md5.pass = syncMd5(input.c_str(), 16);
md5.pass = Md5().compute<string>(input);
md5.algo = "MD5";
destPasswords.push_back(md5);
sha256.pass = syncSha256(input.c_str(), 32);
sha256.pass = Sha256().compute<string>(input);
sha256.algo = "SHA-256";
destPasswords.push_back(sha256);
return;
......@@ -94,7 +95,7 @@ void FileAuthDb::getUserWithPhoneFromBackend(const std::string &phone, const std
}
void FileAuthDb::getPasswordFromBackend(const std::string &id, const std::string &domain,
const std::string &authid, AuthDbListener *listener, AuthDbListener *listener_ref) {
const std::string &authid, AuthDbListener *listener) {
AuthDbResult res = AuthDbResult::PASSWORD_NOT_FOUND;
time_t now = getCurrentTime();
......@@ -108,7 +109,6 @@ void FileAuthDb::getPasswordFromBackend(const std::string &id, const std::string
if (getCachedPassword(key, domain, passwd) == VALID_PASS_FOUND) {
res = AuthDbResult::PASSWORD_FOUND;
}
if (listener_ref) listener_ref->finishVerifyAlgos(passwd);
if (listener) listener->onResult(res, passwd);
}
......@@ -219,3 +219,5 @@ void FileAuthDb::sync() {
}
LOGD("Syncing done");
}
} // namespace flexisip
......@@ -16,11 +16,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "authdb.hh"
#include "soci/mysql/soci-mysql.h"
#include "soci-helper.hh"
#include <thread>
#include <soci/mysql/soci-mysql.h>
#include "soci-helper.hh"
#include "utils/digest.hh"
#include "authdb.hh"
using namespace soci;
// The dreaded chrono::steady_clock which is not supported for gcc < 4.7
......@@ -150,7 +154,7 @@ void SociAuthDB::closeOpenedSessions() {
}
void SociAuthDB::getPasswordWithPool(const string &id, const string &domain,
const string &authid, AuthDbListener *listener, AuthDbListener *listener_ref) {
const string &authid, AuthDbListener *listener) {
vector<passwd_algo_t> passwd;
string unescapedIdStr = urlUnescape(id);
......@@ -171,7 +175,7 @@ void SociAuthDB::getPasswordWithPool(const string &id, const string &domain,
pass.pass = r.get<string>(0);
} else {
string input = unescapedIdStr + ":" + domain + ":" + r.get<string>(0);
pass.pass = syncMd5(input.c_str(), 16);
pass.pass = Md5().compute<string>(input);
}
} else if (r.size() > 1) {
string password = r.get<string>(0);
......@@ -186,11 +190,11 @@ void SociAuthDB::getPasswordWithPool(const string &id, const string &domain,
string input;
input = unescapedIdStr + ":" + domain + ":" + password;
pass.pass = syncMd5(input.c_str(), 16);
pass.pass = Md5().compute<string>(input);
pass.algo = "MD5";
passwd.push_back(pass);
pass.pass = syncSha256(input.c_str(), 32);
pass.pass = Sha256().compute<string>(input);
pass.algo = "SHA-256";
passwd.push_back(pass);
......@@ -205,9 +209,6 @@ void SociAuthDB::getPasswordWithPool(const string &id, const string &domain,
}
});
if (listener_ref) listener_ref->finishVerifyAlgos(passwd);
if (!passwd.empty()) cachePassword(createPasswordKey(id, authid), domain, passwd, mCacheExpire);
if (listener){
listener->onResult(passwd.empty() ? PASSWORD_NOT_FOUND : PASSWORD_FOUND, passwd);
......@@ -335,23 +336,23 @@ void SociAuthDB::notifyAllListeners(std::list<std::tuple<std::string, std::strin
#endif
void SociAuthDB::getPasswordFromBackend(const string &id, const string &domain,
const string &authid, AuthDbListener *listener, AuthDbListener *listener_ref) {
const string &authid, AuthDbListener *listener) {
if (!_connected) connectDatabase();
if (!_connected) {
if (listener) listener->onResult(AUTH_ERROR , "");
if (listener) listener->onResult(AUTH_ERROR , PwList());
return;
}
// create a thread to grab a pool connection and use it to retrieve the auth information
auto func = bind(&SociAuthDB::getPasswordWithPool, this, id, domain, authid, listener, listener_ref);
auto func = bind(&SociAuthDB::getPasswordWithPool, this, id, domain, authid, listener);
bool success = thread_pool->run(func);
if (!success) {
// Enqueue() can fail when the queue is full, so we have to act on that
SLOGE << "[SOCI] Auth queue is full, cannot fullfil password request for " << id << " / " << domain << " / "
<< authid;
if (listener) listener->onResult(AUTH_ERROR, "");
if (listener) listener->onResult(AUTH_ERROR, PwList());
}
}
......
......@@ -17,10 +17,20 @@
*/
#include "authdb.hh"
#include "bctoolbox/crypto.h"
#include "utils/digest.hh"
using namespace std;
using namespace flexisip;
namespace flexisip {
void AuthDbBackend::ListenerToFunctionWrapper::onResult(AuthDbResult result, const std::string &passwd) {
delete this;
}
void AuthDbBackend::ListenerToFunctionWrapper::onResult(AuthDbResult result, const std::vector<passwd_algo_t> &passwd) {
if (mCb) mCb(result, passwd);
delete this;
}
unique_ptr<AuthDbBackend> AuthDbBackend::sUnique;
......@@ -32,12 +42,14 @@ public:
FixedAuthDb() {
}
virtual void getUserWithPhoneFromBackend(const string & phone, const string &domain, AuthDbListener *listener) {
void getUserWithPhoneFromBackend(const string & phone, const string &domain, AuthDbListener *listener) override {
if (listener) listener->onResult(PASSWORD_FOUND, "user@domain.com");
}
virtual void getPasswordFromBackend(const string &id, const string &domain,
const string &authid, AuthDbListener *listener, AuthDbListener *listener_ref) {
if (listener) listener->onResult(PASSWORD_FOUND, "fixed");
void getPasswordFromBackend(const string &id, const string &domain,
const string &authid, AuthDbListener *listener) override {
if (listener) {
listener->onResult(PASSWORD_FOUND, {{"fixed", "CLRTXT"}});
}
}
static void declareConfig(GenericStruct *mc){};
};
......@@ -51,10 +63,6 @@ AuthDbBackend &AuthDbBackend::get() {
sUnique.reset(new FixedAuthDb());
} else if (impl == "file") {
sUnique.reset(new FileAuthDb());
#if ENABLE_ODBC
} else if (impl == "odbc") {
sUnique.reset(new OdbcAuthDb());
#endif
#if ENABLE_SOCI
} else if (impl == "soci") {
sUnique.reset(new SociAuthDB());
......@@ -76,11 +84,7 @@ AuthDbBackend::~AuthDbBackend() {
}
void AuthDbBackend::declareConfig(GenericStruct *mc) {
FileAuthDb::declareConfig(mc);
#if ENABLE_ODBC
OdbcAuthDb::declareConfig(mc);
#endif
#if ENABLE_SOCI
SociAuthDB::declareConfig(mc);
#endif
......@@ -155,12 +159,11 @@ bool AuthDbBackend::cacheUserWithPhone(const string &phone, const string &domain
return true;
}
void AuthDbBackend::getPassword(const string &user, const string &host, const string &auth_username,
AuthDbListener *listener) {
void AuthDbBackend::getPassword(const std::string &user, const std::string &domain, const std::string &auth_username, AuthDbListener *listener) {
// Check for usable cached password
string key(createPasswordKey(user, auth_username));
string key = createPasswordKey(user, auth_username);
vector<passwd_algo_t> pass;
switch (getCachedPassword(key, host, pass)) {
switch (getCachedPassword(key, domain, pass)) {
case VALID_PASS_FOUND:
if (listener) listener->onResult(AuthDbResult::PASSWORD_FOUND, pass);
return;
......@@ -174,31 +177,12 @@ void AuthDbBackend::getPassword(const string &user, const string &host, const st
}
// if we reach here, password wasn't cached: we have to grab the password from the actual backend
getPasswordFromBackend(user, host, auth_username, listener, NULL);
getPasswordFromBackend(user, domain, auth_username, listener);
}
void AuthDbBackend::getPasswordForAlgo(const string &user, const string &host, const string &auth_username,
AuthDbListener *listener, AuthDbListener *listener_ref) {
// Check for usable cached password
string key(createPasswordKey(user, auth_username));
vector<passwd_algo_t> pass;
switch (getCachedPassword(key, host, pass)) {
case VALID_PASS_FOUND:
if (listener) listener->onResult(AuthDbResult::PASSWORD_FOUND, pass);
if (listener_ref) listener_ref->finishVerifyAlgos(pass);
return;
case EXPIRED_PASS_FOUND:
// Might check here if connection is failing
// If it is the case use fallback password and
// return AuthDbResult::PASSWORD_FOUND;
break;
case NO_PASS_FOUND:
break;
}
// if we reach here, password wasn't cached: we have to grab the password from the actual backend
getPasswordFromBackend(user, host, auth_username, listener, listener_ref);
void AuthDbBackend::getPassword(const std::string &user, const std::string &domain, const std::string &auth_username, const ResultCb &cb) {
auto *listener = new ListenerToFunctionWrapper(cb);
getPassword(user, domain, auth_username, listener);
}
void AuthDbBackend::createCachedAccount(const string &user, const string &host, const string &auth_username, const vector<passwd_algo_t> &password,
......@@ -210,28 +194,6 @@ void AuthDbBackend::createCachedAccount(const string &user, const string &host,
}
}
string AuthDbBackend::syncSha256(const char* input,size_t size){
uint8_t a1buf[size];
size_t di;
char out[size*2+1];
bctbx_sha256((const unsigned char*)input, strlen(input),size, a1buf);
for (di = 0; di < size; ++di)
sprintf(out + di * 2, "%02x", a1buf[di]);
out[size*2]='\0';
return out;
}
string AuthDbBackend::syncMd5(const char* input,size_t size){
uint8_t a1buf[size];
size_t di;
char out[size*2+1];
bctbx_md5((const unsigned char*)input, strlen(input), a1buf);
for (di = 0; di < size; ++di)
sprintf(out + di * 2, "%02x", a1buf[di]);
out[size*2]='\0';
return out;
}
void AuthDbBackend::createAccount(const string & user, const string & host, const string &auth_username, const string &password,
int expires, const string & phone_alias) {
// Password here is in mod clrtxt. Calcul passmd5 and passsha256 before createCachedAccount.
......@@ -245,11 +207,11 @@ void AuthDbBackend::createAccount(const string & user, const string & host, cons
string input;
input = user+":"+host+":"+clrtxt.pass;
md5.pass = syncMd5(input.c_str(), 16);
md5.pass = Md5().compute<string>(input);
md5.algo = "MD5";
pass.push_back(md5);
sha256.pass = syncSha256(input.c_str(), 32);
sha256.pass = Sha256().compute<string>(input);
sha256.algo = "SHA-256";
pass.push_back(sha256);
......@@ -317,3 +279,5 @@ void AuthDbBackend::getUsersWithPhonesFromBackend(list<tuple<string,string,AuthD
getUserWithPhoneFromBackend(phone,domain, l);
}
}
} // namespace flexisip
......@@ -27,11 +27,6 @@
#include <vector>
#include <stdio.h>
#if ENABLE_ODBC
#include <sql.h>
#include <sqlext.h>
#endif
#include <map>
#include <set>
#include <thread>
......@@ -57,30 +52,42 @@ struct AuthDbTimings;
class AuthDbListener : public StatFinishListener {
public:
virtual void onResult(AuthDbResult result, const std::string &passwd) = 0;
virtual void onResult(AuthDbResult result, const std::vector<passwd_algo_t> &passwd)=0;
virtual void finishVerifyAlgos(const std::vector<passwd_algo_t> &pass)=0;
virtual void onResult(AuthDbResult result, const std::vector<passwd_algo_t> &passwd) = 0;
virtual ~AuthDbListener();
};
class AuthDbBackend {
static std::unique_ptr<AuthDbBackend> sUnique;
public:
using PwList = std::vector<passwd_algo_t>;
using ResultCb = std::function<void(AuthDbResult, const PwList &)>;
struct CachedPassword {
std::vector<passwd_algo_t> pass;
time_t expire_date;
CachedPassword(const std::vector<passwd_algo_t> &ipass, time_t idate) : pass(ipass), expire_date(idate) {
}
};
virtual ~AuthDbBackend();
// warning: listener may be invoked on authdb backend thread, so listener must be threadsafe somehow!
void getPassword(const std::string &user, const std::string &domain, const std::string &auth_username, AuthDbListener *listener);
void getPassword(const std::string &user, const std::string &domain, const std::string &auth_username, const ResultCb &cb);
void getUserWithPhone(const std::string &phone, const std::string &domain, AuthDbListener *listener);
void getUsersWithPhone(std::list<std::tuple<std::string, std::string, AuthDbListener *>> &creds);
private:
std::map<std::string, std::map<std::string, CachedPassword>> mCachedPasswords;
std::mutex mCachedPasswordMutex;
std::mutex mCachedUserWithPhoneMutex;