Commit d7924e8a authored by Guillaume BIENKOWSKI's avatar Guillaume BIENKOWSKI

- Renamed AuthDb to AuthDbBackend

- Use per-backend configuration items, instead of declaring everything in authdb.cc. This will allow to not clutter the configuration with unused values when some backends are not compiled
parent ed726ef5
......@@ -276,6 +276,30 @@ OdbcAuthDb::OdbcAuthDb() :
#endif
}
void OdbcAuthDb::declareConfig(GenericStruct *mc) {
// ODBC-specific configuration keys
ConfigItemDescriptor items[]={
{ String, "request", "Odbc SQL request to execute to obtain the password \n. "
"Named parameters are :id (the user found in the from header), :domain (the authorization realm) and :authid (the authorization username). "
"The use of the :id parameter is mandatory.",
"select password from accounts where id = :id and domain = :domain and authid=:authid" },
{ Boolean, "odbc-pooling", "Use pooling in ODBC (improves performances). This is not guaranteed to succeed, because if you are using unixODBC, it consults the /etc/odbcinst.ini"
"file in section [ODBC] to check for Pooling=yes/no option. You should make sure that this flag is set before expecting this option to work.", "true" },
{ Integer, "odbc-display-timings-interval", "Display timing statistics after this count of seconds", "0" },
{ Integer, "odbc-display-timings-after-count", "Display timing statistics once the number of samples reach this number.", "0" },
config_item_end
};
mc->addChildrenValues(items);
}
void OdbcAuthDb::setExecuteDirect(const bool value) {
execDirect = value;
}
......@@ -359,6 +383,11 @@ bool OdbcAuthDb::getConnection(const string &id, ConnectionCtx &ctx, AuthDbTimin
return false;
}
steady_clock::time_point tp2=steady_clock::now();
// when debug is not active, the compiler complains about tp1 and tp2 not being used.
(void)tp1;
(void)tp2;
LOGD("SQLAllocHandle: %s : %lu ms", id.c_str(), (unsigned long) duration_cast<milliseconds>(tp2-tp1).count());
// Either:
......
......@@ -21,13 +21,40 @@
using namespace soci;
void SociAuthDB::declareConfig(GenericStruct *mc) {
// ODBC-specific configuration keys
ConfigItemDescriptor items[]={
{ String, "soci-password-request", "Soci SQL request to execute to obtain the password.\n"
"Named parameters are:\n -':id' : the user found in the from header,\n -':domain' : the authorization realm, and\n -':authid' : the authorization username.\n"
"The use of the :id parameter is mandatory.", "select password from accounts where id = :id and domain = :domain and authid=:authid" },
{ Integer, "soci-poolsize", "Size of the pool of connections that Soci will use. We open a thread for each DB query, and this pool will allow each thread to get a connection.\n"
"The threads are blocked until a connection is released back to the pool, so increasing the pool size will allow more connections to occur simultaneously.\n"
"On the other hand, you should not keep too many open connections to your DB at the same time.", "100" },
{ String, "soci-backend", "Choose the type of backend that Soci will use for the connection.\n"
"Depending on your Soci package and the modules you installed, this could be 'mysql', 'oracle', 'postgresql' or something else.", "mysql" },
{ String, "soci-connection-string", "The configuration parameters of the Soci backend.\n"
"The basic format is \"key=value key2=value2\". For a mysql backend, this is a valid config: \"db=mydb user=user password='pass' host=myhost.com\".\n"
"Please refer to the Soci documentation of your backend, for intance: http://soci.sourceforge.net/doc/3.2/backends/mysql.html", "db=mydb user=myuser password='mypass' host=myhost.com" },
config_item_end
};
mc->addChildrenValues(items);
}
SociAuthDB::SociAuthDB() : pool(NULL) {
// TODO: get all these from the configuration
poolSize = 100;
connection_string = "db=mydb user=user password='pass' host=myhost.com";
backend = "mysql";
get_password_request = "select password from accounts where login=:id";
GenericStruct *cr=GenericManager::get()->getRoot();
GenericStruct *ma=cr->get<GenericStruct>("module::Authentication");
poolSize = ma->get< ConfigInt >("soci-poolsize")->read();;
connection_string = ma->get<ConfigString>("soci-connection-string")->read();
backend = ma->get<ConfigString>("soci-backend")->read();
get_password_request = ma->get<ConfigString>("soci-password-request")->read();
pool = new connection_pool(poolSize);
......
......@@ -21,15 +21,15 @@
using namespace ::std;
AuthDb *AuthDb::sUnique = NULL;
AuthDbBackend *AuthDbBackend::sUnique = NULL;
AuthDbListener::~AuthDbListener(){
}
class FixedAuthDb : public AuthDb{
class FixedAuthDb : public AuthDbBackend {
public:
FixedAuthDb(){}
FixedAuthDb(){}
virtual void getPasswordFromBackend(su_root_t *root, const std::string& id, const std::string& domain, const std::string& authid, AuthDbListener *listener)
{
......@@ -37,19 +37,18 @@ public:
listener->mResult=PASSWORD_FOUND;
listener->onResult();
}
static void declareConfig(GenericStruct* mc){};
};
AuthDb* AuthDb::get() {
AuthDbBackend* AuthDbBackend::get() {
if (sUnique == NULL) {
GenericStruct *cr=GenericManager::get()->getRoot();
GenericStruct *ma=cr->get<GenericStruct>("module::Authentication");
const string &impl=ma->get<ConfigString>("db-implementation")->read();
if (impl == "fixed") {
sUnique = new FixedAuthDb();
// } else if (impl == "redis") {
// sUnique = new RedisAuthDb();
} else if (impl == "file") {
sUnique = new FileAuthDb();
sUnique = new FileAuthDb();
#if ENABLE_ODBC
} else if (impl == "odbc") {
sUnique = new OdbcAuthDb();
......@@ -65,23 +64,34 @@ AuthDb* AuthDb::get() {
}
AuthDb::AuthDb() {
AuthDbBackend::AuthDbBackend() {
GenericStruct *cr=GenericManager::get()->getRoot();
GenericStruct *ma=cr->get<GenericStruct>("module::Authentication");
list<string> domains=ma->get<ConfigStringList>("auth-domains")->read();
mCacheExpire = ma->get<ConfigInt>("cache-expire")->read();
}
AuthDb::~AuthDb() {
AuthDbBackend::~AuthDbBackend() {
}
string AuthDb::createPasswordKey(const string &user, const string &host, const string &auth_username) {
void AuthDbBackend::declareConfig(GenericStruct *mc) {
FileAuthDb::declareConfig(mc);
#if ENABLE_ODBC
OdbcAuthDb::declareConfig(mc);
#endif
#if ENABLE_SOCI
SociAuthDB::declareConfig(mc);
#endif
}
string AuthDbBackend::createPasswordKey(const string &user, const string &host, const string &auth_username) {
ostringstream key;
key<<user<<"#"<<auth_username;
return key.str();
}
AuthDb::CacheResult AuthDb::getCachedPassword(const string &key, const string &domain, string &pass) {
AuthDbBackend::CacheResult AuthDbBackend::getCachedPassword(const string &key, const string &domain, string &pass) {
time_t now = getCurrentTime();
auto & passwords=mCachedPasswords[domain];
unique_lock<mutex> lck(mCachedPasswordMutex);
......@@ -98,11 +108,11 @@ AuthDb::CacheResult AuthDb::getCachedPassword(const string &key, const string &d
return NO_PASS_FOUND;
}
void AuthDb::clearCache(){
void AuthDbBackend::clearCache(){
mCachedPasswords.clear();
}
bool AuthDb::cachePassword(const string &key, const string &domain, const string &pass, int expires){
bool AuthDbBackend::cachePassword(const string &key, const string &domain, const string &pass, int expires){
time_t now = getCurrentTime();
map<string, CachedPassword> &passwords=mCachedPasswords[domain];
unique_lock<mutex> lck(mCachedPasswordMutex);
......@@ -117,7 +127,7 @@ bool AuthDb::cachePassword(const string &key, const string &domain, const string
return true;
}
void AuthDb::getPassword(su_root_t *root, const url_t *from, const char *auth_username, AuthDbListener *listener){
void AuthDbBackend::getPassword(su_root_t *root, const url_t *from, const char *auth_username, AuthDbListener *listener){
// Check for usable cached password
string id(from->url_user);
string domain(from->url_host);
......@@ -149,7 +159,7 @@ static void main_thread_async_response_cb(su_root_magic_t *rm, su_msg_r msg,
listener->onResult();
}
void AuthDb::notifyPasswordRetrieved(su_root_t *root, AuthDbListener *listener, AuthDbResult result, const std::string &password) {
void AuthDbBackend::notifyPasswordRetrieved(su_root_t *root, AuthDbListener *listener, AuthDbResult result, const std::string &password) {
if (listener) {
su_msg_r mamc = SU_MSG_R_INIT;
if (-1 == su_msg_create(mamc,
......@@ -185,14 +195,14 @@ void AuthDb::notifyPasswordRetrieved(su_root_t *root, AuthDbListener *listener,
}
}
void AuthDb::createCachedAccount(const url_t *from, const char *auth_username, const char *password, int expires){
void AuthDbBackend::createCachedAccount(const url_t *from, const char *auth_username, const char *password, int expires){
if (from->url_host && from->url_user){
string key=createPasswordKey(from->url_user, from->url_host, auth_username ? auth_username : "");
cachePassword(key,from->url_host,password,expires);
}
}
void AuthDb::createAccount(const url_t *from, const char *auth_username, const char *password, int expires){
void AuthDbBackend::createAccount(const url_t *from, const char *auth_username, const char *password, int expires){
createCachedAccount(from, auth_username, password, expires);
}
......@@ -53,17 +53,19 @@ public:
AuthDbResult mResult;
};
class AuthDb {
static AuthDb *sUnique;
class AuthDbBackend {
static AuthDbBackend *sUnique;
struct CachedPassword {
std::string pass;
time_t expire_date;
CachedPassword(const std::string &ipass, time_t idate):pass(ipass),expire_date(idate){}
};
std::map<std::string, std::map<std::string,CachedPassword>> mCachedPasswords;
std::mutex mCachedPasswordMutex;
protected:
AuthDb();
AuthDbBackend();
enum CacheResult {VALID_PASS_FOUND, EXPIRED_PASS_FOUND, NO_PASS_FOUND};
std::string createPasswordKey(const std::string &user, const std::string &host, const std::string &auth);
bool cachePassword(const std::string &key, const std::string &domain, const std::string &pass, int expires);
......@@ -74,21 +76,24 @@ protected:
void notifyPasswordRetrieved(su_root_t *root, AuthDbListener*listener, AuthDbResult result, const std::string& password);
public:
virtual ~AuthDb();
virtual ~AuthDbBackend();
void getPassword(su_root_t *root, const url_t *from, const char *auth_username, AuthDbListener *listener);
virtual void createAccount(const url_t *from, const char *auth_username, const char *password, int expires);
virtual void getPasswordFromBackend(su_root_t *root, const std::string& id, const std::string& domain, const std::string& authid, AuthDbListener *listener) = 0;
static AuthDb* get();
static AuthDbBackend* get();
/* called by module_auth so that backends can declare their configuration to the ConfigurationManager */
static void declareConfig(GenericStruct * mc);
AuthDb (const AuthDb &);
void operator= (const AuthDb &);
AuthDbBackend (const AuthDbBackend &);
void operator= (const AuthDbBackend &);
};
class FileAuthDb : public AuthDb{
class FileAuthDb : public AuthDbBackend{
private:
std::string mFileString;
time_t mLastSync;
......@@ -100,11 +105,13 @@ public:
FileAuthDb();
virtual void getPasswordFromBackend(su_root_t *root, const std::string& id, const std::string& domain, const std::string& authid, AuthDbListener *listener);
static void declareConfig(GenericStruct * mc) {};
};
#if ENABLE_ODBC
class OdbcAuthDb : public AuthDb {
class OdbcAuthDb : public AuthDbBackend {
~OdbcAuthDb();
const static int fieldLength = 500;
bool mAsynchronousRetrieving;
......@@ -143,21 +150,27 @@ public:
void setExecuteDirect(const bool value);
bool checkConnection();
OdbcAuthDb();
static void declareConfig(GenericStruct * mc);
};
#endif /* ENABLE_ODBC */
#if ENABLE_SOCI
#include "soci.h"
#include "mysql/soci-mysql.h"
class SociAuthDB : public AuthDb {
class SociAuthDB : public AuthDbBackend {
virtual ~SociAuthDB();
public:
SociAuthDB();
void setConnectionParameters(const string& domain, const string &request);
virtual void getPasswordFromBackend(su_root_t *root, const std::string& id, const std::string& domain, const std::string& authid, AuthDbListener *listener);
static void declareConfig(GenericStruct * mc);
private:
void getPasswordWithPool(su_root_t* root, const std::string &id, const std::string &domain, const std::string &authid, AuthDbListener *listener);
......@@ -166,7 +179,6 @@ private:
std::string connection_string;
std::string backend;
std::string get_password_request;
};
#endif /* ENABLE_SOCI */
......
......@@ -289,20 +289,8 @@ public:
"ex2: DRIVER={MySQL};SERVER=host;DATABASE=db;USER=user;PASSWORD=pass;OPTION=3; for a DSN-less connection. "
"ex3: /etc/flexisip/passwd; for a file containing one 'user@domain password' by line.", "" },
{ String, "request", "Odbc SQL request to execute to obtain the password \n. "
"Named parameters are :id (the user found in the from header), :domain (the authorization realm) and :authid (the authorization username). "
"The use of the :id parameter is mandatory.",
"select password from accounts where id = :id and domain = :domain and authid=:authid" },
{ Integer, "nonce-expires", "Expiration time of nonces, in seconds.", "3600" },
{ Boolean, "odbc-pooling", "Use pooling in ODBC (improves performances). This is not guaranteed to succeed, because if you are using unixODBC, it consults the /etc/odbcinst.ini"
"file in section [ODBC] to check for Pooling=yes/no option. You should make sure that this flag is set before expecting this option to work.", "true" },
{ Integer, "odbc-display-timings-interval", "Display timing statistics after this count of seconds", "0" },
{ Integer, "odbc-display-timings-after-count", "Display timing statistics once the number of samples reach this number.", "0" },
{ Integer, "cache-expire", "Duration of the validity of the credentials added to the cache in seconds.", "1800" },
{ Boolean, "hashed-passwords", "True if retrieved passwords from the database are hashed. HA1=MD5(A1) = MD5(username:realm:pass).", "false" },
......@@ -327,6 +315,9 @@ public:
/* modify the default value for "enabled" */
mc->get<ConfigBoolean>("enabled")->setDefault("false");
// Call declareConfig for backends
AuthDbBackend::declareConfig(mc);
mCountAsyncRetrieve=mc->createStat("count-async-retrieve", "Number of asynchronous retrieves.");
mCountSyncRetrieve=mc->createStat("count-sync-retrieve", "Number of synchronous retrieves.");
mCountPassFound=mc->createStat("count-password-found", "Number of passwords found.");
......@@ -409,7 +400,7 @@ public:
if (h && strcasecmp(h->un_value,"yes")==0){
url_t *url=sip->sip_from->a_url;
if (url){
AuthDb::get()->createAccount(url, url->url_user, url->url_password, sip->sip_expires->ex_delta);
AuthDbBackend::get()->createAccount(url, url->url_user, url->url_password, sip->sip_expires->ex_delta);
LOGD("Account created for %s@%s with password %s and expires %i",url->url_user,url->url_host,url->url_password,
(int)sip->sip_expires->ex_delta);
}
......@@ -827,7 +818,7 @@ void Authentication::flexisip_auth_check_digest(auth_mod_t *am,
}
}
AuthDb::get()->getPassword(listener->getRoot(), as->as_user_uri, ar->ar_username, listener);
AuthDbBackend::get()->getPassword(listener->getRoot(), as->as_user_uri, ar->ar_username, listener);
}
......@@ -880,7 +871,7 @@ void Authentication::flexisip_auth_method_digest(auth_mod_t *am,
// sends back its request; this time with the expected authentication credentials.
if (listener->mImmediateRetrievePass) {
SLOGD <<"Searching for "<< as->as_user_uri->url_user<< " password to have it when the authenticated request comes" ;
AuthDb::get()->getPassword(listener->getRoot(), as->as_user_uri, as->as_user_uri->url_user, new DummyListener());
AuthDbBackend::get()->getPassword(listener->getRoot(), as->as_user_uri, as->as_user_uri->url_user, new DummyListener());
}
listener->finish();
return;
......
......@@ -144,7 +144,7 @@ private:
if (r == NULL) {
LOGD("Record doesn't exist. Fork");
string ipassword;
AuthDb *mAuthDb = AuthDb::get();
AuthDbBackend *mAuthDb = AuthDbBackend::get();
mAuthDb->getPassword(gw->mAgent->getRoot(), gw->getFrom()->a_url, gw->getFrom()->a_url->url_user, new OnAuthListener(gw));
} else {
LOGD("Record already exists. Not forked");
......
......@@ -116,7 +116,7 @@ string Monitor::findLocalAddress(const list<string> &nodes) {
void Monitor::createAccounts() {
url_t url;
memset(&url, 0, sizeof(url_t));
AuthDb *authDb = AuthDb::get();
AuthDbBackend *authDb = AuthDbBackend::get();
GenericStruct *cluster = GenericManager::get()->getRoot()->get<GenericStruct>("cluster");
GenericStruct *monitorConf = GenericManager::get()->getRoot()->get<GenericStruct>("monitor");
string salt = monitorConf->get<ConfigString>("password-salt")->read();
......
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