Add authenticator column to quasseluser table
authorBen Rosser <rosser.bjr@gmail.com>
Wed, 30 Dec 2015 06:23:26 +0000 (01:23 -0500)
committerBen Rosser <rosser.bjr@gmail.com>
Sat, 27 May 2017 18:00:11 +0000 (14:00 -0400)
... as additional cross-check when logging in a user.

This will default to storage-based auth.

14 files changed:
src/core/SQL/PostgreSQL/select_authenticator.sql [new file with mode: 0644]
src/core/SQL/PostgreSQL/setup_000_quasseluser.sql
src/core/SQL/PostgreSQL/version/22/upgrade_000_alter_quasseluser_add_authenticator.sql [new file with mode: 0644]
src/core/SQL/SQLite/select_authenticator.sql [new file with mode: 0644]
src/core/SQL/SQLite/setup_000_quasseluser.sql
src/core/SQL/SQLite/version/23/upgrade_000_alter_quasseluser_add_authenticator.sql [new file with mode: 0644]
src/core/core.h
src/core/ldapauthenticator.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_authenticator.sql b/src/core/SQL/PostgreSQL/select_authenticator.sql
new file mode 100644 (file)
index 0000000..637a3d9
--- /dev/null
@@ -0,0 +1,3 @@
+SELECT authenticator
+FROM quasseluser
+WHERE userid = :userid
index 9c99376..0f4c782 100644 (file)
@@ -2,5 +2,6 @@ CREATE TABLE quasseluser (
        userid serial NOT NULL PRIMARY KEY,
        username varchar(64) UNIQUE NOT NULL,
        password TEXT NOT NULL,
-       hashversion integer NOT NULL DEFAULT 0
+       hashversion integer NOT NULL DEFAULT 0,
+       authenticator varchar(64) UNIQUE NOT NULL
 )
diff --git a/src/core/SQL/PostgreSQL/version/22/upgrade_000_alter_quasseluser_add_authenticator.sql b/src/core/SQL/PostgreSQL/version/22/upgrade_000_alter_quasseluser_add_authenticator.sql
new file mode 100644 (file)
index 0000000..50a5203
--- /dev/null
@@ -0,0 +1,2 @@
+ALTER TABLE quasseluser
+ADD COLUMN authenticator varchar(64) NOT NULL DEFAULT "Database";
diff --git a/src/core/SQL/SQLite/select_authenticator.sql b/src/core/SQL/SQLite/select_authenticator.sql
new file mode 100644 (file)
index 0000000..637a3d9
--- /dev/null
@@ -0,0 +1,3 @@
+SELECT authenticator
+FROM quasseluser
+WHERE userid = :userid
index 1833f96..0a325e2 100644 (file)
@@ -2,5 +2,6 @@ CREATE TABLE quasseluser (
        userid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
        username TEXT UNIQUE NOT NULL,
        password TEXT NOT NULL,
-       hashversion INTEGER NOT NULL DEFAULT 0
+       hashversion INTEGER NOT NULL DEFAULT 0,
+       authenticator varchar(64) NOT NULL DEFAULT "Database"
 )
diff --git a/src/core/SQL/SQLite/version/23/upgrade_000_alter_quasseluser_add_authenticator.sql b/src/core/SQL/SQLite/version/23/upgrade_000_alter_quasseluser_add_authenticator.sql
new file mode 100644 (file)
index 0000000..50a5203
--- /dev/null
@@ -0,0 +1,2 @@
+ALTER TABLE quasseluser
+ADD COLUMN authenticator varchar(64) NOT NULL DEFAULT "Database";
index 644e9b9..835e787 100644 (file)
@@ -89,10 +89,21 @@ public:
     /**
      * \param userName The user's login name
      * \param password The user's uncrypted password
+     * \param authenticator The name of the auth provider service used to log the user in, defaults to "Database".
      * \return The user's ID if valid; 0 otherwise
      */
-    static inline UserId addUser(const QString &userName, const QString &password) {
-        return instance()->_storage->addUser(userName, password);
+    static inline UserId addUser(const QString &userName, const QString &password, const QString &authenticator = "Database") {
+        return instance()->_storage->addUser(userName, password, authenticator);
+    }
+    
+    //! Does a comparison test against the authenticator in the database and the authenticator currently in use for a UserID.
+    /**
+     * \param userid The user's ID (note: not login name).
+     * \param authenticator The name of the auth provider service used to log the user in, defaults to "Database".
+     * \return True if the userid was configured with the passed authenticator, false otherwise.
+     */
+    static inline bool checkAuthProvider(const UserId userid, const QString &authenticator) {
+        return instance()->_storage->getUserAuthenticator(userid) == authenticator;
     }
 
     //! Change a user's password
index 378fc4b..90b7e89 100644 (file)
@@ -118,11 +118,17 @@ UserId LdapAuthenticator::validateUser(const QString &username, const QString &p
 
     // If auth succeeds, but the user has not logged into quassel previously, make
     // a new user for them and return that ID.
-    // Users created via LDAP have empty usernames.
+    // Users created via LDAP have empty passwords, but authenticator column = LDAP.
+    // On the other hand, if auth succeeds and the user already exists, do a final
+    // cross-check to confirm we're using the right auth provider.
     UserId quasselID = Core::validateUser(username, QString());
     if (!quasselID.isValid())
     {
-        return Core::addUser(username, QString());
+        return Core::addUser(username, QString(), displayName());
+    }
+    else if (!(Core::checkAuthProvider(quasselID, displayName())))
+    {
+        return 0;
     }
     return quasselID;
 }
index cbbd473..6a7f788 100644 (file)
@@ -210,13 +210,14 @@ bool PostgreSqlStorage::setupSchemaVersion(int version)
 }
 
 
-UserId PostgreSqlStorage::addUser(const QString &user, const QString &password)
+UserId PostgreSqlStorage::addUser(const QString &user, const QString &password, const QString &authenticator)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("insert_quasseluser"));
     query.bindValue(":username", user);
     query.bindValue(":password", hashPassword(password));
     query.bindValue(":hashversion", Storage::HashVersion::Latest);
+    query.bindValue(":authenticator", authenticator);
     safeExec(query);
     if (!watchQuery(query))
         return 0;
@@ -286,6 +287,21 @@ UserId PostgreSqlStorage::getUserId(const QString &user)
     }
 }
 
+QString PostgreSqlStorage::getUserAuthenticator(const UserId userid)
+{
+    QSqlQuery query(logDb());
+    query.prepare(queryString("select_authenticator"));
+    query.bindValue(":userid", userid.toInt());
+    safeExec(query);
+    watchQuery(query);
+
+    if (query.first()) {
+        return query.value(0).toString();
+    }
+    else {
+        return QString("");
+    }
+}
 
 UserId PostgreSqlStorage::internalUser()
 {
index c96687e..530e7aa 100644 (file)
@@ -48,11 +48,12 @@ public slots:
 
     /* User handling */
 
-    virtual UserId addUser(const QString &user, const QString &password);
+    virtual UserId addUser(const QString &user, const QString &password, const QString &authenticator = "Database");
     virtual bool updateUser(UserId user, const QString &password);
     virtual void renameUser(UserId user, const QString &newName);
     virtual UserId validateUser(const QString &user, const QString &password);
     virtual UserId getUserId(const QString &username);
+    virtual QString getUserAuthenticator(const UserId userid);
     virtual UserId internalUser();
     virtual void delUser(UserId user);
     virtual void setUserSetting(UserId userId, const QString &settingName, const QVariant &data);
index d302b4d..f945690 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/select_authenticator.sql</file>
     <file>./SQL/PostgreSQL/select_authuser.sql</file>
     <file>./SQL/PostgreSQL/select_bufferByName.sql</file>
     <file>./SQL/PostgreSQL/select_bufferExists.sql</file>
     <file>./SQL/PostgreSQL/version/20/upgrade_004_add_lastseenmsgid_constraint.sql</file>
     <file>./SQL/PostgreSQL/version/21/upgrade_000_add_function_backlog_lastmsgid_update.sql</file>
     <file>./SQL/PostgreSQL/version/21/upgrade_001_add_trigger_backlog_lastmsgid_update.sql</file>
+    <file>./SQL/PostgreSQL/version/22/upgrade_000_alter_quasseluser_add_authenticator.sql</file>
     <file>./SQL/SQLite/delete_backlog_by_uid.sql</file>
     <file>./SQL/SQLite/delete_backlog_for_buffer.sql</file>
     <file>./SQL/SQLite/delete_backlog_for_network.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_authenticator.sql</file>
     <file>./SQL/SQLite/select_authuser.sql</file>
     <file>./SQL/SQLite/select_bufferByName.sql</file>
     <file>./SQL/SQLite/select_bufferExists.sql</file>
     <file>./SQL/SQLite/version/21/upgrade_006_alter_table_buffer_new_rename_to_buffer.sql</file>
     <file>./SQL/SQLite/version/22/upgrade_000_add_trigger_backlog_lastmsgid_update_direct_insert.sql</file>
     <file>./SQL/SQLite/version/22/upgrade_001_add_trigger_backlog_lastmsgid_update_direct_update.sql</file>
+    <file>./SQL/SQLite/version/23/upgrade_000_alter_quasseluser_add_authenticator.sql</file>
 </qresource>
 </RCC>
index 10c5f1b..3457c1e 100644 (file)
@@ -116,7 +116,7 @@ bool SqliteStorage::setupSchemaVersion(int version)
 }
 
 
-UserId SqliteStorage::addUser(const QString &user, const QString &password)
+UserId SqliteStorage::addUser(const QString &user, const QString &password, const QString &authenticator)
 {
     QSqlDatabase db = logDb();
     UserId uid;
@@ -131,6 +131,7 @@ UserId SqliteStorage::addUser(const QString &user, const QString &password)
         query.bindValue(":username", user);
         query.bindValue(":password", hashPassword(password));
         query.bindValue(":hashversion", Storage::HashVersion::Latest);
+        query.bindValue(":authenticator", authenticator);
         lockForWrite();
         safeExec(query);
         if (query.lastError().isValid() && query.lastError().number() == 19) { // user already exists - sadly 19 seems to be the general constraint violation error...
@@ -240,6 +241,26 @@ UserId SqliteStorage::getUserId(const QString &username)
     return userId;
 }
 
+QString SqliteStorage::getUserAuthenticator(const UserId userid)
+{
+    QString authenticator = QString("");
+
+    {
+        QSqlQuery query(logDb());
+        query.prepare(queryString("select_authenticator"));
+        query.bindValue(":userid", userid.toInt());
+
+        lockForRead();
+        safeExec(query);
+
+        if (query.first()) {
+            authenticator = query.value(0).toString();
+        }
+    }
+    unlock();
+
+    return authenticator;
+}
 
 UserId SqliteStorage::internalUser()
 {
index 9a12fbe..8287f38 100644 (file)
@@ -49,11 +49,12 @@ public slots:
     // TODO: Add functions for configuring the backlog handling, i.e. defining auto-cleanup settings etc
 
     /* User handling */
-    virtual UserId addUser(const QString &user, const QString &password);
+    virtual UserId addUser(const QString &user, const QString &password, const QString &authenticator = "Database");
     virtual bool updateUser(UserId user, const QString &password);
     virtual void renameUser(UserId user, const QString &newName);
     virtual UserId validateUser(const QString &user, const QString &password);
     virtual UserId getUserId(const QString &username);
+    virtual QString getUserAuthenticator(const UserId userid);
     virtual UserId internalUser();
     virtual void delUser(UserId user);
     virtual void setUserSetting(UserId userId, const QString &settingName, const QVariant &data);
index 71492d5..29a8df8 100644 (file)
@@ -103,7 +103,7 @@ public slots:
      *  \param password The cleartext password for the new user
      *  \return The new user's UserId
      */
-    virtual UserId addUser(const QString &user, const QString &password) = 0;
+    virtual UserId addUser(const QString &user, const QString &password, const QString &authenticator = "Database") = 0;
 
     //! Update a core user's password.
     /** \param user     The user's id
@@ -131,6 +131,13 @@ public slots:
      */
     virtual UserId getUserId(const QString &username) = 0;
 
+    //! Get the authentication provider for a given user.
+    /** \param username  The username to validate
+     *  \return The name of the auth provider if the UserId exists, "" otherwise.
+     */
+    virtual QString getUserAuthenticator(const UserId userid) = 0;
+
+
     //! Determine the UserId of the internal user
     /** \return A valid UserId if the password matches the username; 0 else
      */