Cache strict sysident mappings
authorMichael Marley <michael@michaelmarley.com>
Wed, 4 Apr 2018 12:25:14 +0000 (08:25 -0400)
committerManuel Nickschas <sputnick@quassel-irc.org>
Mon, 7 May 2018 20:38:41 +0000 (22:38 +0200)
To avoid unnecessary database hits, we store a mapping of all permitted
strict sysidents in memory. This mapping is reloaded on SIGHUP.

A miss will make a call to the database.

Co-authored-by: Sai Nane <esainane+github@gmail.com>
Co-authored-by: Michael Marley <michael@michaelmarley.com>
12 files changed:
src/core/SQL/PostgreSQL/select_all_authusernames.sql [new file with mode: 0644]
src/core/SQL/SQLite/select_all_authusernames.sql [new file with mode: 0644]
src/core/core.cpp
src/core/core.h
src/core/coreapplication.cpp
src/core/coresession.cpp
src/core/postgresqlstorage.cpp
src/core/postgresqlstorage.h
src/core/sql.qrc
src/core/sqlitestorage.cpp
src/core/sqlitestorage.h
src/core/storage.h

diff --git a/src/core/SQL/PostgreSQL/select_all_authusernames.sql b/src/core/SQL/PostgreSQL/select_all_authusernames.sql
new file mode 100644 (file)
index 0000000..1f480ba
--- /dev/null
@@ -0,0 +1,2 @@
+SELECT userid, username
+FROM quasseluser;
diff --git a/src/core/SQL/SQLite/select_all_authusernames.sql b/src/core/SQL/SQLite/select_all_authusernames.sql
new file mode 100644 (file)
index 0000000..1f480ba
--- /dev/null
@@ -0,0 +1,2 @@
+SELECT userid, username
+FROM quasseluser;
index 73fde97..aa52063 100644 (file)
@@ -236,8 +236,12 @@ void Core::init()
     connect(&_v6server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
     if (!startListening()) exit(1);  // TODO make this less brutal
 
     connect(&_v6server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
     if (!startListening()) exit(1);  // TODO make this less brutal
 
-    if (Quassel::isOptionSet("oidentd"))
+    if (Quassel::isOptionSet("oidentd")) {
         _oidentdConfigGenerator = new OidentdConfigGenerator(Quassel::isOptionSet("oidentd-strict"), this);
         _oidentdConfigGenerator = new OidentdConfigGenerator(Quassel::isOptionSet("oidentd-strict"), this);
+        if (Quassel::isOptionSet("oidentd-strict")) {
+            cacheSysident();
+        }
+    }
 }
 
 
 }
 
 
@@ -329,6 +333,7 @@ QString Core::setupCore(const QString &adminUser, const QString &adminPassword,
 
     quInfo() << qPrintable(tr("Creating admin user..."));
     _storage->addUser(adminUser, adminPassword);
 
     quInfo() << qPrintable(tr("Creating admin user..."));
     _storage->addUser(adminUser, adminPassword);
+    cacheSysident();
     startListening(); // TODO check when we need this
     return QString();
 }
     startListening(); // TODO check when we need this
     return QString();
 }
@@ -548,6 +553,31 @@ bool Core::reloadCerts()
 #endif
 }
 
 #endif
 }
 
+void Core::cacheSysident() {
+    if(isConfigured()) {
+        instance()->_authusernames = instance()->_storage->getAllAuthusernames();
+    }
+}
+
+QString Core::strictSysident(UserId user) {
+    QMap<UserId, QString> *allAuthusernames = &instance()->_authusernames;
+    auto authusername = allAuthusernames->find(user);
+    if (authusername == allAuthusernames->end()) {
+        // A new user got added since we last pulled our cache from the database.
+        // There's no way to avoid a database hit - we don't even know the authname!
+        cacheSysident();
+        authusername = allAuthusernames->find(user);
+        if (authusername == allAuthusernames->end()) {
+            // ...something very weird is going on if we ended up here (an active CoreSession without a corresponding database entry?)
+            QDebug d = qWarning();
+            d << "Unable to find authusername for UserId" << user;
+            d.nospace();
+            d << ", this should never happen!";
+            return "unknown"; // Should we just terminate the program instead?
+        }
+    }
+    return *authusername;
+}
 
 bool Core::startListening()
 {
 
 bool Core::startListening()
 {
index a29d672..91aafd2 100644 (file)
@@ -501,6 +501,12 @@ public:
         return instance()->_storage->getAuthusername(user);
     }
 
         return instance()->_storage->getAuthusername(user);
     }
 
+    //! Get a usable sysident for the given user in oidentd-strict mode
+    /** \param user    The user to retrieve the sysident for
+     *  \return The authusername
+     */
+    QString strictSysident(UserId user);
+
 
     //! Get a Hash of all last seen message ids
     /** This Method is called when the Quassel Core is started to restore the lastSeenMsgIds
 
     //! Get a Hash of all last seen message ids
     /** This Method is called when the Quassel Core is started to restore the lastSeenMsgIds
@@ -584,6 +590,8 @@ public:
      */
     static bool reloadCerts();
 
      */
     static bool reloadCerts();
 
+    static void cacheSysident();
+
     static QVariantList backendInfo();
     static QVariantList authenticatorInfo();
 
     static QVariantList backendInfo();
     static QVariantList authenticatorInfo();
 
@@ -667,6 +675,7 @@ private:
     DeferredSharedPtr<Storage>       _storage;        ///< Active storage backend
     DeferredSharedPtr<Authenticator> _authenticator;  ///< Active authenticator
     QTimer _storageSyncTimer;
     DeferredSharedPtr<Storage>       _storage;        ///< Active storage backend
     DeferredSharedPtr<Authenticator> _authenticator;  ///< Active authenticator
     QTimer _storageSyncTimer;
+    QMap<UserId, QString> _authusernames;
 
 #ifdef HAVE_SSL
     SslServer _server, _v6server;
 
 #ifdef HAVE_SSL
     SslServer _server, _v6server;
index 91c4171..7f4388b 100644 (file)
@@ -56,7 +56,8 @@ bool CoreApplicationInternal::init()
     _coreCreated = true;
 
     Quassel::registerReloadHandler([]() {
     _coreCreated = true;
 
     Quassel::registerReloadHandler([]() {
-        // Currently, only reloading SSL certificates is supported
+        // Currently, only reloading SSL certificates and the sysident cache is supported
+        Core::cacheSysident();
         return Core::reloadCerts();
     });
 
         return Core::reloadCerts();
     });
 
index b263739..41bf2d6 100644 (file)
@@ -509,8 +509,7 @@ void CoreSession::createIdentity(const Identity &identity, const QVariantMap &ad
 }
 
 const QString CoreSession::strictSysident() {
 }
 
 const QString CoreSession::strictSysident() {
-    const QString authusername = Core::getAuthusername(_user);
-    return authusername;
+    return Core::instance()->strictSysident(_user);
 }
 
 void CoreSession::createIdentity(const CoreIdentity &identity)
 }
 
 void CoreSession::createIdentity(const CoreIdentity &identity)
index 48ee466..f976f09 100644 (file)
@@ -1702,6 +1702,19 @@ QList<Message> PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId
     return messagelist;
 }
 
     return messagelist;
 }
 
+QMap<UserId, QString> PostgreSqlStorage::getAllAuthusernames() {
+    QMap<UserId, QString> authusernames;
+    QSqlQuery query(logDb());
+    query.prepare(queryString("select_all_authusernames"));
+    safeExec(query);
+    watchQuery(query);
+
+    while (query.next()) {
+        authusernames[query.value(0).toInt()] = query.value(1).toString();
+    }
+    return authusernames;
+}
+
 const QString PostgreSqlStorage::getAuthusername(UserId user) {
     QString authusername;
     QSqlQuery query(logDb());
 const QString PostgreSqlStorage::getAuthusername(UserId user) {
     QString authusername;
     QSqlQuery query(logDb());
index ad09ff9..2445c61 100644 (file)
@@ -106,6 +106,7 @@ public slots:
     QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
 
     /* Sysident handling */
     QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
 
     /* Sysident handling */
+    virtual QMap<UserId, QString> getAllAuthusernames();
     virtual const QString getAuthusername(UserId user);
 
 protected:
     virtual const QString getAuthusername(UserId user);
 
 protected:
index 597df0f..edaaa32 100644 (file)
@@ -30,6 +30,7 @@
     <file>./SQL/PostgreSQL/migrate_write_quasseluser.sql</file>
     <file>./SQL/PostgreSQL/migrate_write_sender.sql</file>
     <file>./SQL/PostgreSQL/migrate_write_usersetting.sql</file>
     <file>./SQL/PostgreSQL/migrate_write_quasseluser.sql</file>
     <file>./SQL/PostgreSQL/migrate_write_sender.sql</file>
     <file>./SQL/PostgreSQL/migrate_write_usersetting.sql</file>
+    <file>./SQL/PostgreSQL/select_all_authusernames.sql</file>
     <file>./SQL/PostgreSQL/select_authenticator.sql</file>
     <file>./SQL/PostgreSQL/select_authuser.sql</file>
     <file>./SQL/PostgreSQL/select_authusername.sql</file>
     <file>./SQL/PostgreSQL/select_authenticator.sql</file>
     <file>./SQL/PostgreSQL/select_authuser.sql</file>
     <file>./SQL/PostgreSQL/select_authusername.sql</file>
     <file>./SQL/SQLite/migrate_read_quasseluser.sql</file>
     <file>./SQL/SQLite/migrate_read_sender.sql</file>
     <file>./SQL/SQLite/migrate_read_usersetting.sql</file>
     <file>./SQL/SQLite/migrate_read_quasseluser.sql</file>
     <file>./SQL/SQLite/migrate_read_sender.sql</file>
     <file>./SQL/SQLite/migrate_read_usersetting.sql</file>
+    <file>./SQL/SQLite/select_all_authusernames.sql</file>
     <file>./SQL/SQLite/select_authenticator.sql</file>
     <file>./SQL/SQLite/select_authuser.sql</file>
     <file>./SQL/SQLite/select_authusername.sql</file>
     <file>./SQL/SQLite/select_authenticator.sql</file>
     <file>./SQL/SQLite/select_authuser.sql</file>
     <file>./SQL/SQLite/select_authusername.sql</file>
index 0962fac..69c41b8 100644 (file)
@@ -1820,6 +1820,28 @@ QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId las
     return messagelist;
 }
 
     return messagelist;
 }
 
+QMap<UserId, QString> SqliteStorage::getAllAuthusernames()
+{
+    QMap<UserId, QString> authusernames;
+
+    QSqlDatabase db = logDb();
+    db.transaction();
+    {
+        QSqlQuery query(db);
+        query.prepare(queryString("select_all_authusernames"));
+
+        lockForRead();
+        safeExec(query);
+        watchQuery(query);
+        while (query.next()) {
+            authusernames[query.value(0).toInt()] = query.value(1).toString();
+        }
+    }
+    db.commit();
+    unlock();
+    return authusernames;
+}
+
 const QString SqliteStorage::getAuthusername(UserId user) {
     QString authusername;
     QSqlQuery query(logDb());
 const QString SqliteStorage::getAuthusername(UserId user) {
     QString authusername;
     QSqlQuery query(logDb());
index 15d5437..fcc85ff 100644 (file)
@@ -107,6 +107,7 @@ public slots:
     QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
 
     /* Sysident handling */
     QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
 
     /* Sysident handling */
+    virtual QMap<UserId, QString> getAllAuthusernames();
     virtual const QString getAuthusername(UserId user);
 
 protected:
     virtual const QString getAuthusername(UserId user);
 
 protected:
index c77e9eb..c809a7f 100644 (file)
@@ -442,6 +442,11 @@ public slots:
      */
     virtual QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) = 0;
 
      */
     virtual QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) = 0;
 
+    //! Fetch all authusernames
+    /** \return      Map of all current UserIds to permitted idents
+     */
+    virtual QMap<UserId, QString> getAllAuthusernames() = 0;
+
     //! Get the auth username associated with a userId
     /** \param user  The user to retrieve the username for
      *  \return      The username for the user
     //! Get the auth username associated with a userId
     /** \param user  The user to retrieve the username for
      *  \return      The username for the user