Implement authenticator class used for logging in users
authorBen Rosser <rosser.bjr@gmail.com>
Sat, 14 Nov 2015 19:44:36 +0000 (14:44 -0500)
committerBen Rosser <rosser.bjr@gmail.com>
Sat, 27 May 2017 17:56:37 +0000 (13:56 -0400)
Added authenticator setup info to the core, also added a new core
setup dialog page for authenticators.

Wrote a SqlAuthenticator that simply wraps the existing
storage-based auth.

28 files changed:
CMakeLists.txt
cmake/FindLdap.cmake [new file with mode: 0644]
src/client/clientauthhandler.cpp
src/client/clientauthhandler.h
src/client/coreconnection.cpp
src/client/coreconnection.h
src/common/protocol.h
src/common/protocols/datastream/datastreampeer.cpp
src/common/protocols/legacy/legacypeer.cpp
src/core/CMakeLists.txt
src/core/authenticator.cpp [new file with mode: 0644]
src/core/authenticator.h [new file with mode: 0644]
src/core/core.cpp
src/core/core.h
src/core/coreauthhandler.cpp
src/core/coresettings.cpp
src/core/coresettings.h
src/core/ldapauthenticator.cpp [new file with mode: 0644]
src/core/ldapauthenticator.h [new file with mode: 0644]
src/core/sqlauthenticator.cpp [new file with mode: 0644]
src/core/sqlauthenticator.h [new file with mode: 0644]
src/qtui/CMakeLists.txt
src/qtui/coreconfigwizard.cpp
src/qtui/coreconfigwizard.h
src/qtui/mainwin.cpp
src/qtui/mainwin.h
src/qtui/ui/coreconfigwizardauthenticationselectionpage.ui [new file with mode: 0644]
src/qtui/ui/coreconfigwizardsyncpage.ui

index e8beb5b..42f2ab3 100644 (file)
@@ -133,6 +133,10 @@ if (LINK_EXTRA)
 endif()
 
 
 endif()
 
 
+# LDAP Authentication (and other authentication backends).
+####################################################################
+option(WITH_LDAP     "Enable LDAP authentication support if present on system" ON)
+
 # Setup CMake
 #####################################################################
 
 # Setup CMake
 #####################################################################
 
@@ -514,6 +518,19 @@ if (CMAKE_COMPILER_IS_GNUCXX)
     string(REPLACE "-ansi" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
 endif()
 
     string(REPLACE "-ansi" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
 endif()
 
+# Setup LDAP Authentication support.
+#####################################################################
+if(WITH_LDAP)
+       find_package(Ldap)
+       if(LDAP_FOUND)
+               message(STATUS "Enabling LDAP authentication support")
+               set(HAVE_LDAP true)
+       else(LDAP_FOUND)
+               message(STATUS "Disabling LDAP authentication support")
+       endif(LDAP_FOUND)
+else(WITH_LDAP)
+       message(STATUS "Not enabling LDAP authentication support")
+endif(WITH_LDAP)
 
 # Setup KDE / KDE Frameworks
 #####################################################################
 
 # Setup KDE / KDE Frameworks
 #####################################################################
diff --git a/cmake/FindLdap.cmake b/cmake/FindLdap.cmake
new file mode 100644 (file)
index 0000000..e29d6a2
--- /dev/null
@@ -0,0 +1,43 @@
+# Copied from https://raw.github.com/facebook/hiphop-php/master/CMake/FindLdap.cmake
+
+# - Try to find the LDAP client libraries
+# Once done this will define
+#
+#  LDAP_FOUND - system has libldap
+#  LDAP_INCLUDE_DIR - the ldap include directory
+#  LDAP_LIBRARIES - libldap + liblber (if found) library
+#  LBER_LIBRARIES - liblber library
+
+if(LDAP_INCLUDE_DIR AND LDAP_LIBRARIES)
+    # Already in cache, be silent
+    set(Ldap_FIND_QUIETLY TRUE)
+endif(LDAP_INCLUDE_DIR AND LDAP_LIBRARIES)
+
+if(UNIX)
+   FIND_PATH(LDAP_INCLUDE_DIR ldap.h)
+   FIND_LIBRARY(LDAP_LIBRARIES NAMES ldap)
+   FIND_LIBRARY(LBER_LIBRARIES NAMES lber)
+
+else(UNIX)
+   FIND_PATH(LDAP_INCLUDE_DIR winldap.h)
+   FIND_LIBRARY(LDAP_LIBRARIES NAMES wldap32)
+endif(UNIX)
+
+if(LDAP_INCLUDE_DIR AND LDAP_LIBRARIES)
+   set(LDAP_FOUND TRUE)
+   if(LBER_LIBRARIES)
+     set(LDAP_LIBRARIES ${LDAP_LIBRARIES} ${LBER_LIBRARIES})
+   endif(LBER_LIBRARIES)
+endif(LDAP_INCLUDE_DIR AND LDAP_LIBRARIES)
+
+if(LDAP_FOUND)
+   if(NOT Ldap_FIND_QUIETLY)
+      message(STATUS "Found ldap: ${LDAP_LIBRARIES}")
+   endif(NOT Ldap_FIND_QUIETLY)
+else(LDAP_FOUND)
+   if (Ldap_FIND_REQUIRED)
+        message(FATAL_ERROR "Could NOT find ldap")
+   endif (Ldap_FIND_REQUIRED)
+endif(LDAP_FOUND)
+
+MARK_AS_ADVANCED(LDAP_INCLUDE_DIR LDAP_LIBRARIES LBER_LIBRARIES LDAP_DIR)
index c8ed735..fc6156d 100644 (file)
@@ -303,6 +303,7 @@ void ClientAuthHandler::handle(const ClientRegistered &msg)
 {
     _coreConfigured = msg.coreConfigured;
     _backendInfo = msg.backendInfo;
 {
     _coreConfigured = msg.coreConfigured;
     _backendInfo = msg.backendInfo;
+    _authBackendInfo = msg.authBackendInfo;
 
     Client::setCoreFeatures(static_cast<Quassel::Features>(msg.coreFeatures));
 
 
     Client::setCoreFeatures(static_cast<Quassel::Features>(msg.coreFeatures));
 
@@ -321,7 +322,7 @@ void ClientAuthHandler::onConnectionReady()
 
     if (!_coreConfigured) {
         // start wizard
 
     if (!_coreConfigured) {
         // start wizard
-        emit startCoreSetup(_backendInfo);
+        emit startCoreSetup(_backendInfo, _authBackendInfo);
     }
     else // TODO: check if we need LoginEnabled
         login();
     }
     else // TODO: check if we need LoginEnabled
         login();
index 9c9a522..d6e54cd 100644 (file)
@@ -70,7 +70,7 @@ signals:
 #endif
 
     void encrypted(bool isEncrypted = true);
 #endif
 
     void encrypted(bool isEncrypted = true);
-    void startCoreSetup(const QVariantList &backendInfo);
+    void startCoreSetup(const QVariantList &backendInfo, const QVariantList &authBackendInfo);
     void coreSetupSuccessful();
     void coreSetupFailed(const QString &error);
 
     void coreSetupSuccessful();
     void coreSetupFailed(const QString &error);
 
@@ -113,6 +113,7 @@ private:
     RemotePeer *_peer;
     bool _coreConfigured;
     QVariantList _backendInfo;
     RemotePeer *_peer;
     bool _coreConfigured;
     QVariantList _backendInfo;
+    QVariantList _authBackendInfo;
     CoreAccount _account;
     bool _probing;
     bool _legacy;
     CoreAccount _account;
     bool _probing;
     bool _legacy;
index e916d7f..b0c4feb 100644 (file)
@@ -395,7 +395,7 @@ void CoreConnection::connectToCurrentAccount()
     connect(_authHandler, SIGNAL(errorPopup(QString)), SIGNAL(connectionErrorPopup(QString)), Qt::QueuedConnection);
     connect(_authHandler, SIGNAL(statusMessage(QString)), SIGNAL(connectionMsg(QString)));
     connect(_authHandler, SIGNAL(encrypted(bool)), SIGNAL(encrypted(bool)));
     connect(_authHandler, SIGNAL(errorPopup(QString)), SIGNAL(connectionErrorPopup(QString)), Qt::QueuedConnection);
     connect(_authHandler, SIGNAL(statusMessage(QString)), SIGNAL(connectionMsg(QString)));
     connect(_authHandler, SIGNAL(encrypted(bool)), SIGNAL(encrypted(bool)));
-    connect(_authHandler, SIGNAL(startCoreSetup(QVariantList)), SIGNAL(startCoreSetup(QVariantList)));
+    connect(_authHandler, SIGNAL(startCoreSetup(QVariantList, QVariantList)), SIGNAL(startCoreSetup(QVariantList, QVariantList)));
     connect(_authHandler, SIGNAL(coreSetupFailed(QString)), SIGNAL(coreSetupFailed(QString)));
     connect(_authHandler, SIGNAL(coreSetupSuccessful()), SIGNAL(coreSetupSuccess()));
     connect(_authHandler, SIGNAL(userAuthenticationRequired(CoreAccount*,bool*,QString)), SIGNAL(userAuthenticationRequired(CoreAccount*,bool*,QString)));
     connect(_authHandler, SIGNAL(coreSetupFailed(QString)), SIGNAL(coreSetupFailed(QString)));
     connect(_authHandler, SIGNAL(coreSetupSuccessful()), SIGNAL(coreSetupSuccess()));
     connect(_authHandler, SIGNAL(userAuthenticationRequired(CoreAccount*,bool*,QString)), SIGNAL(userAuthenticationRequired(CoreAccount*,bool*,QString)));
index 216e925..f381c33 100644 (file)
@@ -97,7 +97,7 @@ signals:
     void progressValueChanged(int value);
     void progressTextChanged(const QString &);
 
     void progressValueChanged(int value);
     void progressTextChanged(const QString &);
 
-    void startCoreSetup(const QVariantList &backendInfo);
+    void startCoreSetup(const QVariantList &backendInfo, const QVariantList &authBackendInfo);
     void coreSetupSuccess();
     void coreSetupFailed(const QString &error);
 
     void coreSetupSuccess();
     void coreSetupFailed(const QString &error);
 
index c7cbcb3..b686a51 100644 (file)
@@ -81,17 +81,21 @@ struct ClientDenied : public HandshakeMessage
 
 struct ClientRegistered : public HandshakeMessage
 {
 
 struct ClientRegistered : public HandshakeMessage
 {
-    inline ClientRegistered(quint32 coreFeatures, bool coreConfigured, const QVariantList &backendInfo, bool sslSupported)
+    inline ClientRegistered(quint32 coreFeatures, bool coreConfigured, const QVariantList &backendInfo, const QVariantList &authBackendInfo, bool sslSupported)
     : coreFeatures(coreFeatures)
     , coreConfigured(coreConfigured)
     , backendInfo(backendInfo)
     : coreFeatures(coreFeatures)
     , coreConfigured(coreConfigured)
     , backendInfo(backendInfo)
+    , authBackendInfo(authBackendInfo)
     , sslSupported(sslSupported)
     {}
 
     quint32 coreFeatures;
     bool coreConfigured;
     , sslSupported(sslSupported)
     {}
 
     quint32 coreFeatures;
     bool coreConfigured;
+    
+    // The authBackendInfo should be optional!
     QVariantList backendInfo; // TODO: abstract this better
     QVariantList backendInfo; // TODO: abstract this better
-
+    QVariantList authBackendInfo;
+    
     // this is only used by the LegacyProtocol in compat mode
     bool sslSupported;
 };
     // this is only used by the LegacyProtocol in compat mode
     bool sslSupported;
 };
@@ -99,13 +103,15 @@ struct ClientRegistered : public HandshakeMessage
 
 struct SetupData : public HandshakeMessage
 {
 
 struct SetupData : public HandshakeMessage
 {
-    inline SetupData(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData)
-    : adminUser(adminUser), adminPassword(adminPassword), backend(backend), setupData(setupData) {}
+    inline SetupData(const QString &adminUser, const QString &adminPassword, const QString &backend, const QString &authenticator, const QVariantMap &setupData, const QVariantMap &authSetupData)
+    : adminUser(adminUser), adminPassword(adminPassword), backend(backend), authenticator(authenticator), setupData(setupData), authSetupData(authSetupData) {}
 
     QString adminUser;
     QString adminPassword;
     QString backend;
 
     QString adminUser;
     QString adminPassword;
     QString backend;
+       QString authenticator;
     QVariantMap setupData;
     QVariantMap setupData;
+       QVariantMap authSetupData;
 };
 
 
 };
 
 
index af2fcb4..b21b9df 100644 (file)
@@ -124,12 +124,12 @@ void DataStreamPeer::handleHandshakeMessage(const QVariantList &mapData)
     }
 
     else if (msgType == "ClientInitAck") {
     }
 
     else if (msgType == "ClientInitAck") {
-        handle(ClientRegistered(m["CoreFeatures"].toUInt(), m["Configured"].toBool(), m["StorageBackends"].toList(), false)); // SupportsSsl is obsolete
+        handle(ClientRegistered(m["CoreFeatures"].toUInt(), m["Configured"].toBool(), m["StorageBackends"].toList(), m["AuthBackends"].toList(), false)); // SupportsSsl is obsolete
     }
 
     else if (msgType == "CoreSetupData") {
         QVariantMap map = m["SetupData"].toMap();
     }
 
     else if (msgType == "CoreSetupData") {
         QVariantMap map = m["SetupData"].toMap();
-        handle(SetupData(map["AdminUser"].toString(), map["AdminPasswd"].toString(), map["Backend"].toString(), map["ConnectionProperties"].toMap()));
+        handle(SetupData(map["AdminUser"].toString(), map["AdminPasswd"].toString(), map["Backend"].toString(), map["AuthBackend"].toString(), map["ConnectionProperties"].toMap(), map["AuthProperties"].toMap()));
     }
 
     else if (msgType == "CoreSetupReject") {
     }
 
     else if (msgType == "CoreSetupReject") {
@@ -187,6 +187,7 @@ void DataStreamPeer::dispatch(const ClientRegistered &msg) {
     m["MsgType"] = "ClientInitAck";
     m["CoreFeatures"] = msg.coreFeatures;
     m["StorageBackends"] = msg.backendInfo;
     m["MsgType"] = "ClientInitAck";
     m["CoreFeatures"] = msg.coreFeatures;
     m["StorageBackends"] = msg.backendInfo;
+    m["AuthBackends"] = msg.authBackendInfo;
     m["LoginEnabled"] = m["Configured"] = msg.coreConfigured;
 
     writeMessage(m);
     m["LoginEnabled"] = m["Configured"] = msg.coreConfigured;
 
     writeMessage(m);
@@ -201,6 +202,11 @@ void DataStreamPeer::dispatch(const SetupData &msg)
     map["Backend"] = msg.backend;
     map["ConnectionProperties"] = msg.setupData;
 
     map["Backend"] = msg.backend;
     map["ConnectionProperties"] = msg.setupData;
 
+    // Auth backend properties.
+    // XXX: make these optional using core features.
+    map["AuthBackend"] = msg.authenticator;
+    map["AuthProperties"] = msg.authSetupData;
+    
     QVariantMap m;
     m["MsgType"] = "CoreSetupData";
     m["SetupData"] = map;
     QVariantMap m;
     m["MsgType"] = "CoreSetupData";
     m["SetupData"] = map;
index 9ceb460..8f53fc1 100644 (file)
@@ -170,12 +170,12 @@ void LegacyPeer::handleHandshakeMessage(const QVariant &msg)
             socket()->setProperty("UseCompression", true);
 #endif
 
             socket()->setProperty("UseCompression", true);
 #endif
 
-        handle(ClientRegistered(m["CoreFeatures"].toUInt(), m["Configured"].toBool(), m["StorageBackends"].toList(), m["SupportSsl"].toBool()));
+        handle(ClientRegistered(m["CoreFeatures"].toUInt(), m["Configured"].toBool(), m["StorageBackends"].toList(), m["AuthBackends"].toList(), m["SupportSsl"].toBool()));
     }
 
     else if (msgType == "CoreSetupData") {
         QVariantMap map = m["SetupData"].toMap();
     }
 
     else if (msgType == "CoreSetupData") {
         QVariantMap map = m["SetupData"].toMap();
-        handle(SetupData(map["AdminUser"].toString(), map["AdminPasswd"].toString(), map["Backend"].toString(), map["ConnectionProperties"].toMap()));
+        handle(SetupData(map["AdminUser"].toString(), map["AdminPasswd"].toString(), map["Backend"].toString(), map["AuthBackend"].toString(), map["ConnectionProperties"].toMap(), map["AuthProperties"].toMap()));
     }
 
     else if (msgType == "CoreSetupReject") {
     }
 
     else if (msgType == "CoreSetupReject") {
@@ -242,6 +242,7 @@ void LegacyPeer::dispatch(const ClientRegistered &msg) {
     m["MsgType"] = "ClientInitAck";
     m["CoreFeatures"] = msg.coreFeatures;
     m["StorageBackends"] = msg.backendInfo;
     m["MsgType"] = "ClientInitAck";
     m["CoreFeatures"] = msg.coreFeatures;
     m["StorageBackends"] = msg.backendInfo;
+    m["AuthBackends"] = msg.authBackendInfo;
 
     // FIXME only in compat mode
     m["ProtocolVersion"] = protocolVersion;
 
     // FIXME only in compat mode
     m["ProtocolVersion"] = protocolVersion;
@@ -264,6 +265,11 @@ void LegacyPeer::dispatch(const SetupData &msg)
     map["AdminPasswd"] = msg.adminPassword;
     map["Backend"] = msg.backend;
     map["ConnectionProperties"] = msg.setupData;
     map["AdminPasswd"] = msg.adminPassword;
     map["Backend"] = msg.backend;
     map["ConnectionProperties"] = msg.setupData;
+    
+    // Auth backend properties.
+    // XXX: make these optional using core features.
+    map["AuthBackend"] = msg.authenticator;
+    map["AuthProperties"] = msg.authSetupData;
 
     QVariantMap m;
     m["MsgType"] = "CoreSetupData";
 
     QVariantMap m;
     m["MsgType"] = "CoreSetupData";
index 39a7ceb..8d2e9db 100644 (file)
@@ -2,6 +2,7 @@
 
 set(SOURCES
     abstractsqlstorage.cpp
 
 set(SOURCES
     abstractsqlstorage.cpp
+       authenticator.cpp
     core.cpp
     corealiasmanager.cpp
     coreapplication.cpp
     core.cpp
     corealiasmanager.cpp
     coreapplication.cpp
@@ -34,6 +35,7 @@ set(SOURCES
     oidentdconfiggenerator.cpp
     postgresqlstorage.cpp
     sessionthread.cpp
     oidentdconfiggenerator.cpp
     postgresqlstorage.cpp
     sessionthread.cpp
+    sqlauthenticator.cpp
     sqlitestorage.cpp
     storage.cpp
 
     sqlitestorage.cpp
     storage.cpp
 
diff --git a/src/core/authenticator.cpp b/src/core/authenticator.cpp
new file mode 100644 (file)
index 0000000..018c0cd
--- /dev/null
@@ -0,0 +1,26 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2015 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   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, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#include "authenticator.h"
+
+Authenticator::Authenticator(QObject *parent)
+    : QObject(parent)
+{
+}
\ No newline at end of file
diff --git a/src/core/authenticator.h b/src/core/authenticator.h
new file mode 100644 (file)
index 0000000..8029631
--- /dev/null
@@ -0,0 +1,92 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2015 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   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, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#ifndef AUTHENTICATOR_H
+#define AUTHENTICATOR_H
+
+#include <QtCore>
+
+#include "types.h"
+
+class Authenticator : public QObject {
+  
+       Q_OBJECT
+       
+public:
+    Authenticator(QObject *parent = 0);
+    virtual ~Authenticator() {};
+
+    enum State {
+        IsReady,               // ready to go
+        NeedsSetup,            // need basic setup (ask the user for input)
+        NotAvailable   // remove the authenticator backend from the list of avaliable authenticators.
+    };
+
+
+public slots:
+       // General
+       
+    //! Check if the authenticator type is available.
+    /** An authenticator subclass should return true if it can be successfully used, i.e. if all
+     *  prerequisites are in place.
+     * \return True if and only if the authenticator class can be successfully used.
+     */
+    virtual bool isAvailable() const = 0;
+
+    //! Returns the display name of the authenticator backend
+    /** \return A string that can be used by the client to name the authenticator backend */
+    virtual QString displayName() const = 0;
+       
+    //! Returns a description of this authenticator backend
+    /** \return A string that can be displayed by the client to describe the authenticator */
+    virtual QString description() const = 0;
+
+    //! Returns a list of properties required to use the authenticator backend
+    virtual QStringList setupKeys() const = 0;
+
+    //! Returns a map where the keys are are properties to use the authenticator backend
+    /*  the values are QVariants with default values */
+    virtual QVariantMap setupDefaults() const = 0;
+
+    //! Setup the authenticator provider.
+    /** This prepares the authenticator provider (e.g. create tables, etc.) for use within Quassel.
+     *  \param settings   Hostname, port, username, password, ...
+     *  \return True if and only if the authenticator provider was initialized successfully.
+     */
+    virtual bool setup(const QVariantMap &settings = QVariantMap()) = 0;
+
+    //! Initialize the authenticator provider
+    /** \param settings   Hostname, port, username, password, ...
+     *  \return the State the authenticator backend is now in (see authenticator::State)
+     */
+    virtual State init(const QVariantMap &settings = QVariantMap()) = 0;
+
+    //! Validate a username with a given password.
+    /** \param user     The username to validate
+     *  \param password The user's alleged password
+     *  \return A valid UserId if the password matches the username; 0 else
+     */
+    virtual UserId validateUser(const QString &user, const QString &password) = 0;
+       
+private:
+       
+};
+  
+#endif
\ No newline at end of file
index ad9eab8..c145f5b 100644 (file)
@@ -29,6 +29,7 @@
 #include "network.h"
 #include "postgresqlstorage.h"
 #include "quassel.h"
 #include "network.h"
 #include "postgresqlstorage.h"
 #include "quassel.h"
+#include "sqlauthenticator.h"
 #include "sqlitestorage.h"
 #include "util.h"
 
 #include "sqlitestorage.h"
 #include "util.h"
 
@@ -83,7 +84,8 @@ void Core::destroy()
 
 Core::Core()
     : QObject(),
 
 Core::Core()
     : QObject(),
-      _storage(0)
+      _storage(0),
+      _authenticator(0)
 {
 #ifdef HAVE_UMASK
     umask(S_IRWXG | S_IRWXO);
 {
 #ifdef HAVE_UMASK
     umask(S_IRWXG | S_IRWXO);
@@ -168,7 +170,8 @@ Core::Core()
     }
 
     registerStorageBackends();
     }
 
     registerStorageBackends();
-
+       registerAuthenticatorBackends();
+       
     connect(&_storageSyncTimer, SIGNAL(timeout()), this, SLOT(syncStorage()));
     _storageSyncTimer.start(10 * 60 * 1000); // 10 minutes
 }
     connect(&_storageSyncTimer, SIGNAL(timeout()), this, SLOT(syncStorage()));
     _storageSyncTimer.start(10 * 60 * 1000); // 10 minutes
 }
@@ -181,10 +184,16 @@ void Core::init()
     QVariantMap dbsettings = cs.storageSettings().toMap();
     _configured = initStorage(dbsettings.value("Backend").toString(), dbsettings.value("ConnectionProperties").toMap());
 
     QVariantMap dbsettings = cs.storageSettings().toMap();
     _configured = initStorage(dbsettings.value("Backend").toString(), dbsettings.value("ConnectionProperties").toMap());
 
+       // Not entirely sure what is 'legacy' about the above, but it seems to be the way things work!
+       QVariantMap authSettings = cs.authSettings().toMap();
+       initAuthenticator(authSettings.value("AuthBackend").toString(), authSettings.value("ConnectionProperties").toMap());
+       
     if (Quassel::isOptionSet("select-backend")) {
         selectBackend(Quassel::optionValue("select-backend"));
         exit(0);
     }
     if (Quassel::isOptionSet("select-backend")) {
         selectBackend(Quassel::optionValue("select-backend"));
         exit(0);
     }
+    
+    // TODO: add --select-authenticator command line option and code.
 
     if (!_configured) {
         if (!_storageBackends.count()) {
 
     if (!_configured) {
         if (!_storageBackends.count()) {
@@ -281,13 +290,13 @@ void Core::restoreState()
 
 /*** Core Setup ***/
 
 
 /*** Core Setup ***/
 
-QString Core::setup(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData)
+QString Core::setup(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData, const QString &authBackend, const QVariantMap &authSetupData)
 {
 {
-    return instance()->setupCore(adminUser, adminPassword, backend, setupData);
+    return instance()->setupCore(adminUser, adminPassword, backend, setupData, authBackend, authSetupData);
 }
 
 
 }
 
 
-QString Core::setupCore(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData)
+QString Core::setupCore(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData, const QString &authBackend, const QVariantMap &authSetupData)
 {
     if (_configured)
         return tr("Core is already configured! Not configuring again...");
 {
     if (_configured)
         return tr("Core is already configured! Not configuring again...");
@@ -302,6 +311,7 @@ QString Core::setupCore(const QString &adminUser, const QString &adminPassword,
     if (!saveBackendSettings(backend, setupData)) {
         return tr("Could not save backend settings, probably a permission problem.");
     }
     if (!saveBackendSettings(backend, setupData)) {
         return tr("Could not save backend settings, probably a permission problem.");
     }
+       saveAuthBackendSettings(authBackend, authSetupData);
 
     quInfo() << qPrintable(tr("Creating admin user..."));
     _storage->addUser(adminUser, adminPassword);
 
     quInfo() << qPrintable(tr("Creating admin user..."));
     _storage->addUser(adminUser, adminPassword);
@@ -322,7 +332,7 @@ QString Core::setupCoreForInternalUsage()
     }
 
     // mono client currently needs sqlite
     }
 
     // mono client currently needs sqlite
-    return setupCore("AdminUser", QString::number(pass), "SQLite", QVariantMap());
+    return setupCore("AdminUser", QString::number(pass), "SQLite", QVariantMap(), "StorageAuth", QVariantMap());
 }
 
 
 }
 
 
@@ -347,7 +357,6 @@ bool Core::registerStorageBackend(Storage *backend)
     }
 }
 
     }
 }
 
-
 void Core::unregisterStorageBackends()
 {
     foreach(Storage *s, _storageBackends.values()) {
 void Core::unregisterStorageBackends()
 {
     foreach(Storage *s, _storageBackends.values()) {
@@ -363,6 +372,43 @@ void Core::unregisterStorageBackend(Storage *backend)
     backend->deleteLater();
 }
 
     backend->deleteLater();
 }
 
+// Authentication handling, now independent from storage.
+// Register and unregister authenticators.
+
+void Core::registerAuthenticatorBackends()
+{
+    // Register new authentication backends here!
+    //registerAuthenticatorBackend(new LdapAuthenticator(this));
+    registerAuthenticatorBackend(new SqlAuthenticator(this));
+    
+}
+
+bool Core::registerAuthenticatorBackend(Authenticator *authenticator)
+{
+       if (authenticator->isAvailable())
+       {
+               _authenticatorBackends[authenticator->displayName()] = authenticator;
+               return true;
+       } else {
+               authenticator->deleteLater();
+               return false;
+        }
+}
+
+void Core::unregisterAuthenticatorBackends()
+{
+       foreach(Authenticator* a, _authenticatorBackends.values())
+       {
+               a->deleteLater();
+       }
+       _authenticatorBackends.clear();
+}
+
+void Core::unregisterAuthenticatorBackend(Authenticator *backend)
+{
+       _authenticatorBackends.remove(backend->displayName());
+       backend->deleteLater();
+}
 
 // old db settings:
 // "Type" => "sqlite"
 
 // old db settings:
 // "Type" => "sqlite"
@@ -404,6 +450,43 @@ bool Core::initStorage(const QString &backend, const QVariantMap &settings, bool
     return true;
 }
 
     return true;
 }
 
+// XXX: TODO: Apparently, this is legacy?
+bool Core::initAuthenticator(const QString &backend, const QVariantMap &settings, bool setup)
+{
+    _authenticator = 0;
+    
+    if (backend.isEmpty()) {
+            return false;
+    }
+    
+    Authenticator *authenticator = 0;
+    if (_authenticatorBackends.contains(backend)) {
+        authenticator = _authenticatorBackends[backend];
+    }
+    else {
+        qCritical() << "Selected auth backend is not available:" << backend;
+        return false;
+    }
+
+    Authenticator::State authState = authenticator->init(settings);
+    switch (authState) {
+    case Authenticator::NeedsSetup:
+        if (!setup)
+            return false;  // trigger setup process
+        if (authenticator->setup(settings))
+            return initAuthenticator(backend, settings, false);
+    // if initialization wasn't successful, we quit to keep from coming up unconfigured
+    case Authenticator::NotAvailable:
+        qCritical() << "FATAL: Selected auth backend is not available:" << backend;
+        exit(EXIT_FAILURE);
+    case Authenticator::IsReady:
+        // delete all other backends
+        _authenticatorBackends.remove(backend);
+        unregisterAuthenticatorBackends();
+    }
+    _authenticator = authenticator;
+    return true;       
+}
 
 void Core::syncStorage()
 {
 
 void Core::syncStorage()
 {
@@ -689,6 +772,19 @@ QVariantList Core::backendInfo()
     return backends;
 }
 
     return backends;
 }
 
+QVariantList Core::authenticatorInfo()
+{
+    QVariantList backends;
+    foreach(const Authenticator *backend, instance()->_authenticatorBackends.values()) {
+        QVariantMap v;
+        v["DisplayName"] = backend->displayName();
+        v["Description"] = backend->description();
+        v["SetupKeys"] = backend->setupKeys();
+        v["SetupDefaults"] = backend->setupDefaults();
+        backends.append(v);
+    }
+    return backends;
+}
 
 // migration / backend selection
 bool Core::selectBackend(const QString &backend)
 
 // migration / backend selection
 bool Core::selectBackend(const QString &backend)
@@ -905,6 +1001,14 @@ bool Core::saveBackendSettings(const QString &backend, const QVariantMap &settin
     return s.sync();
 }
 
     return s.sync();
 }
 
+void Core::saveAuthBackendSettings(const QString &backend, const QVariantMap &settings)
+{
+    QVariantMap dbsettings;
+    dbsettings["AuthBackend"] = backend;
+    dbsettings["ConnectionProperties"] = settings;
+    CoreSettings().setAuthSettings(dbsettings);
+}
+
 
 QVariantMap Core::promptForSettings(const Storage *storage)
 {
 
 QVariantMap Core::promptForSettings(const Storage *storage)
 {
index f974645..f63a32b 100644 (file)
@@ -34,6 +34,7 @@
 #  include <QTcpServer>
 #endif
 
 #  include <QTcpServer>
 #endif
 
+#include "authenticator.h"
 #include "bufferinfo.h"
 #include "message.h"
 #include "oidentdconfiggenerator.h"
 #include "bufferinfo.h"
 #include "message.h"
 #include "oidentdconfiggenerator.h"
@@ -74,6 +75,15 @@ public:
         return instance()->_storage->validateUser(userName, password);
     }
 
         return instance()->_storage->validateUser(userName, password);
     }
 
+    //! Authenticate user against auth backend
+    /**
+     * \param userName The user's login name
+     * \param password The user's uncrypted password
+     * \return The user's ID if valid; 0 otherwise
+     */
+    static inline UserId authenticateUser(const QString &userName, const QString &password) {
+        return instance()->_authenticator->validateUser(userName, password);
+    }
 
     //! Change a user's password
     /**
 
     //! Change a user's password
     /**
@@ -503,6 +513,7 @@ public:
     static bool reloadCerts();
 
     static QVariantList backendInfo();
     static bool reloadCerts();
 
     static QVariantList backendInfo();
+    static QVariantList authenticatorInfo();
 
     /**
      * Checks if a storage backend is the default storage backend. This
 
     /**
      * Checks if a storage backend is the default storage backend. This
@@ -517,7 +528,7 @@ public:
         return (backend->displayName() == "SQLite") ? true : false;
     }
 
         return (backend->displayName() == "SQLite") ? true : false;
     }
 
-    static QString setup(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData);
+    static QString setup(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData, const QString &authBackend, const QVariantMap &authSetupMap);
 
     static inline QTimer &syncTimer() { return instance()->_storageSyncTimer; }
 
 
     static inline QTimer &syncTimer() { return instance()->_storageSyncTimer; }
 
@@ -531,7 +542,7 @@ public slots:
      */
     void syncStorage();
     void setupInternalClientSession(InternalPeer *clientConnection);
      */
     void syncStorage();
     void setupInternalClientSession(InternalPeer *clientConnection);
-    QString setupCore(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData);
+    QString setupCore(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData, const QString &authBackend, const QVariantMap &authSetupMap);
 
 signals:
     //! Sent when a BufferInfo is updated in storage.
 
 signals:
     //! Sent when a BufferInfo is updated in storage.
@@ -550,7 +561,8 @@ private slots:
     void clientDisconnected();
 
     bool initStorage(const QString &backend, const QVariantMap &settings, bool setup = false);
     void clientDisconnected();
 
     bool initStorage(const QString &backend, const QVariantMap &settings, bool setup = false);
-
+    bool initAuthenticator(const QString &backend, const QVariantMap &settings, bool setup = false);
+    
     void socketError(QAbstractSocket::SocketError err, const QString &errorString);
     void setupClientSession(RemotePeer *, UserId);
 
     void socketError(QAbstractSocket::SocketError err, const QString &errorString);
     void setupClientSession(RemotePeer *, UserId);
 
@@ -571,15 +583,25 @@ private:
     bool registerStorageBackend(Storage *);
     void unregisterStorageBackends();
     void unregisterStorageBackend(Storage *);
     bool registerStorageBackend(Storage *);
     void unregisterStorageBackends();
     void unregisterStorageBackend(Storage *);
+    
+    void registerAuthenticatorBackends();
+    bool registerAuthenticatorBackend(Authenticator *);
+    void unregisterAuthenticatorBackends();
+    void unregisterAuthenticatorBackend(Authenticator *);
+    
     bool selectBackend(const QString &backend);
     bool createUser();
     bool saveBackendSettings(const QString &backend, const QVariantMap &settings);
     bool selectBackend(const QString &backend);
     bool createUser();
     bool saveBackendSettings(const QString &backend, const QVariantMap &settings);
+    void saveAuthBackendSettings(const QString &backend, const QVariantMap &settings);
     QVariantMap promptForSettings(const Storage *storage);
 
 private:
     QSet<CoreAuthHandler *> _connectingClients;
     QHash<UserId, SessionThread *> _sessions;
     QVariantMap promptForSettings(const Storage *storage);
 
 private:
     QSet<CoreAuthHandler *> _connectingClients;
     QHash<UserId, SessionThread *> _sessions;
+
+    // Have both a storage backend and an authenticator backend.
     Storage *_storage;
     Storage *_storage;
+    Authenticator *_authenticator;
     QTimer _storageSyncTimer;
 
 #ifdef HAVE_SSL
     QTimer _storageSyncTimer;
 
 #ifdef HAVE_SSL
@@ -591,6 +613,7 @@ private:
     OidentdConfigGenerator *_oidentdConfigGenerator;
 
     QHash<QString, Storage *> _storageBackends;
     OidentdConfigGenerator *_oidentdConfigGenerator;
 
     QHash<QString, Storage *> _storageBackends;
+    QHash<QString, Authenticator *> _authenticatorBackends;
 
     QDateTime _startTime;
 
 
     QDateTime _startTime;
 
index 90f4ad8..af5ef47 100644 (file)
@@ -172,12 +172,16 @@ void CoreAuthHandler::handle(const RegisterClient &msg)
     }
 
     QVariantList backends;
     }
 
     QVariantList backends;
+       QVariantList authenticators;
     bool configured = Core::isConfigured();
     if (!configured)
     bool configured = Core::isConfigured();
     if (!configured)
+       {
         backends = Core::backendInfo();
         backends = Core::backendInfo();
+               authenticators = Core::authenticatorInfo();
+       }
 
     // useSsl is only used for the legacy protocol
 
     // useSsl is only used for the legacy protocol
-    _peer->dispatch(ClientRegistered(Quassel::features(), configured, backends, useSsl));
+    _peer->dispatch(ClientRegistered(Quassel::features(), configured, backends, authenticators, useSsl));
 
     if (_legacy && useSsl)
         startSsl();
 
     if (_legacy && useSsl)
         startSsl();
@@ -191,7 +195,7 @@ void CoreAuthHandler::handle(const SetupData &msg)
     if (!checkClientRegistered())
         return;
 
     if (!checkClientRegistered())
         return;
 
-    QString result = Core::setup(msg.adminUser, msg.adminPassword, msg.backend, msg.setupData);
+    QString result = Core::setup(msg.adminUser, msg.adminPassword, msg.backend, msg.setupData, msg.authenticator, msg.authSetupData);
     if (!result.isEmpty())
         _peer->dispatch(SetupFailed(result));
     else
     if (!result.isEmpty())
         _peer->dispatch(SetupFailed(result));
     else
@@ -204,7 +208,14 @@ void CoreAuthHandler::handle(const Login &msg)
     if (!checkClientRegistered())
         return;
 
     if (!checkClientRegistered())
         return;
 
-    UserId uid = Core::validateUser(msg.user, msg.password);
+    //UserId uid = Core::validateUser(msg.user, msg.password);
+    UserId uid = Core::authenticateUser(msg.user, msg.password);
+       
+       // Try doing direct database auth if the provider failed, first.
+       if (uid == 0) {
+               uid = Core::validateUser(msg.user, msg.password);
+       }
+    
     if (uid == 0) {
         quInfo() << qPrintable(tr("Invalid login attempt from %1 as \"%2\"").arg(socket()->peerAddress().toString(), msg.user));
         _peer->dispatch(LoginFailed(tr("<b>Invalid username or password!</b><br>The username/password combination you supplied could not be found in the database.")));
     if (uid == 0) {
         quInfo() << qPrintable(tr("Invalid login attempt from %1 as \"%2\"").arg(socket()->peerAddress().toString(), msg.user));
         _peer->dispatch(LoginFailed(tr("<b>Invalid username or password!</b><br>The username/password combination you supplied could not be found in the database.")));
index c54dbad..243374b 100644 (file)
@@ -43,6 +43,15 @@ QVariant CoreSettings::storageSettings(const QVariant &def)
     return localValue("StorageSettings", def);
 }
 
     return localValue("StorageSettings", def);
 }
 
+QVariant CoreSettings::authSettings(const QVariant &def)
+{
+       return localValue("AuthSettings", def);
+}
+
+void CoreSettings::setAuthSettings(const QVariant &data)
+{
+       setLocalValue("AuthSettings", data);
+}      
 
 // FIXME remove
 QVariant CoreSettings::oldDbSettings()
 
 // FIXME remove
 QVariant CoreSettings::oldDbSettings()
index f1ae6bc..bbb19f9 100644 (file)
@@ -32,6 +32,9 @@ public:
     void setStorageSettings(const QVariant &data);
     QVariant storageSettings(const QVariant &def = QVariant());
 
     void setStorageSettings(const QVariant &data);
     QVariant storageSettings(const QVariant &def = QVariant());
 
+       void setAuthSettings(const QVariant &data);
+       QVariant authSettings(const QVariant &def = QVariant());
+
     QVariant oldDbSettings();  // FIXME remove
 
     void setCoreState(const QVariant &data);
     QVariant oldDbSettings();  // FIXME remove
 
     void setCoreState(const QVariant &data);
diff --git a/src/core/ldapauthenticator.cpp b/src/core/ldapauthenticator.cpp
new file mode 100644 (file)
index 0000000..40085e2
--- /dev/null
@@ -0,0 +1,37 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2015 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   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, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#include "ldapauthenticator.h"
+
+#include "network.h"
+#include "quassel.h"
+
+LdapAuthenticator::LdapAuthenticator(QObject *parent)
+    : LdapAuthenticator(parent),
+    _port(-1)
+{
+}
+
+
+LdapAuthenticator::~LdapAuthenticator()
+{
+}
+
+// XXX: TODO: write the actual LDAP code.
\ No newline at end of file
diff --git a/src/core/ldapauthenticator.h b/src/core/ldapauthenticator.h
new file mode 100644 (file)
index 0000000..c6ee7f1
--- /dev/null
@@ -0,0 +1,60 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2015 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   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, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#ifndef LDAPAUTHENTICATOR_H
+#define LDAPAUTHENTICATOR_H
+
+#include "authenticator.h"
+
+class LdapAuthenticator : public Authenticator
+{
+    Q_OBJECT
+
+public:
+    LdapAuthenticator(QObject *parent = 0);
+    virtual ~LdapAuthenticator();
+
+public slots:
+    /* General */
+    virtual bool isAvailable() const;
+    virtual QString displayName() const;
+    virtual QString description() const;
+    virtual QStringList setupKeys() const;
+    virtual QVariantMap setupDefaults() const;
+
+    /* User handling */
+    virtual UserId getUserId(const QString &username);
+protected:
+       // Protecte methods for retrieving info about the LDAP connection.
+       inline virtual QString hostName() { return _hostName; }
+       inline virtual int port() { return _port; }
+       inline virtual QString bindDN() { return _bindDN; }
+       inline virtual QString baseDN() { return _baseDN; }
+       
+private:
+    QString _hostName;
+    int _port;
+       QString _bindDN;
+       QString _baseDN;
+};
+
+
+#endif
diff --git a/src/core/sqlauthenticator.cpp b/src/core/sqlauthenticator.cpp
new file mode 100644 (file)
index 0000000..fe8fffc
--- /dev/null
@@ -0,0 +1,76 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2015 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   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, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#include "sqlauthenticator.h"
+
+#include "logger.h"
+#include "network.h"
+#include "quassel.h"
+
+#include "core.h"
+
+SqlAuthenticator::SqlAuthenticator(QObject *parent)
+    : Authenticator(parent)
+{
+}
+
+
+SqlAuthenticator::~SqlAuthenticator()
+{
+}
+
+bool SqlAuthenticator::isAvailable() const
+{
+    // XXX: probably this should query the current storage (see the ::init routine too).
+    return true;
+}
+
+QString SqlAuthenticator::displayName() const
+{
+    // We identify the backend to use for the monolithic core by its displayname.
+    // so only change this string if you _really_ have to and make sure the core
+    // setup for the mono client still works ;)
+    return QString("Database");
+}
+
+QString SqlAuthenticator::description() const
+{
+    return tr("Do not auth against any remote authentication service, but instead save a hashed and salted password "
+              "in the selected database.");
+}
+
+UserId SqlAuthenticator::validateUser(const QString &user, const QString &password)
+{
+    return Core::validateUser(user, password);
+}
+
+bool SqlAuthenticator::setup(const QVariantMap &settings)
+{
+       return true;
+}
+
+Authenticator::State SqlAuthenticator::init(const QVariantMap &settings)
+{
+       // TODO: FIXME: this should check if the storage provider is ready, but I don't
+       // know if there's an exposed way to do that at the moment.
+       
+       quInfo() << qPrintable(displayName()) << "Authenticator is ready.";
+       return IsReady;
+}
\ No newline at end of file
diff --git a/src/core/sqlauthenticator.h b/src/core/sqlauthenticator.h
new file mode 100644 (file)
index 0000000..1b71ee2
--- /dev/null
@@ -0,0 +1,52 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2015 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   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, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#ifndef SQLAUTHENTICATOR_H
+#define SQLAUTHENTICATOR_H
+
+#include "authenticator.h"
+
+class SqlAuthenticator : public Authenticator
+{
+    Q_OBJECT
+
+public:
+    SqlAuthenticator(QObject *parent = 0);
+    virtual ~SqlAuthenticator();
+
+public slots:
+    /* General */
+    bool isAvailable() const;
+    QString displayName() const;
+    QString description() const;
+    virtual inline QStringList setupKeys() const { return QStringList(); }
+    virtual inline QVariantMap setupDefaults() const { return QVariantMap(); }
+
+    bool setup(const QVariantMap &settings = QVariantMap());
+    State init(const QVariantMap &settings = QVariantMap());
+    UserId validateUser(const QString &user, const QString &password);
+    
+    /* User handling */
+    //virtual UserId getUserId(const QString &username);
+
+};
+
+
+#endif
index 5fee3df..319e0d7 100644 (file)
@@ -60,6 +60,7 @@ set(FORMS
     channellistdlg.ui
     chatviewsearchbar.ui
     coreconfigwizardintropage.ui
     channellistdlg.ui
     chatviewsearchbar.ui
     coreconfigwizardintropage.ui
+    coreconfigwizardauthenticationselectionpage.ui
     coreconfigwizardadminuserpage.ui
     coreconfigwizardstorageselectionpage.ui
     coreconfigwizardsyncpage.ui
     coreconfigwizardadminuserpage.ui
     coreconfigwizardstorageselectionpage.ui
     coreconfigwizardsyncpage.ui
index 6873528..d2ce4b8 100644 (file)
@@ -27,7 +27,7 @@
 #include "coreconfigwizard.h"
 #include "coreconnection.h"
 
 #include "coreconfigwizard.h"
 #include "coreconnection.h"
 
-CoreConfigWizard::CoreConfigWizard(CoreConnection *connection, const QList<QVariant> &backends, QWidget *parent)
+CoreConfigWizard::CoreConfigWizard(CoreConnection *connection, const QList<QVariant> &backends, const QList<QVariant> &authenticators, QWidget *parent)
     : QWizard(parent),
     _connection(connection)
 {
     : QWizard(parent),
     _connection(connection)
 {
@@ -36,12 +36,17 @@ CoreConfigWizard::CoreConfigWizard(CoreConnection *connection, const QList<QVari
 
     foreach(const QVariant &v, backends)
     _backends[v.toMap()["DisplayName"].toString()] = v;
 
     foreach(const QVariant &v, backends)
     _backends[v.toMap()["DisplayName"].toString()] = v;
+    
+    foreach(const QVariant &v, authenticators)
+    _authenticators[v.toMap()["DisplayName"].toString()] = v;
 
     setPage(IntroPage, new CoreConfigWizardPages::IntroPage(this));
     setPage(AdminUserPage, new CoreConfigWizardPages::AdminUserPage(this));
 
     setPage(IntroPage, new CoreConfigWizardPages::IntroPage(this));
     setPage(AdminUserPage, new CoreConfigWizardPages::AdminUserPage(this));
+    setPage(AuthenticationSelectionPage, new CoreConfigWizardPages::AuthenticationSelectionPage(_authenticators, this));
     setPage(StorageSelectionPage, new CoreConfigWizardPages::StorageSelectionPage(_backends, this));
     syncPage = new CoreConfigWizardPages::SyncPage(this);
     setPage(StorageSelectionPage, new CoreConfigWizardPages::StorageSelectionPage(_backends, this));
     syncPage = new CoreConfigWizardPages::SyncPage(this);
-    connect(syncPage, SIGNAL(setupCore(const QString &, const QVariantMap &)), SLOT(prepareCoreSetup(const QString &, const QVariantMap &)));
+    connect(syncPage, SIGNAL(setupCore(const QString &, const QVariantMap &, const QString &, const QVariantMap &)), 
+                       SLOT(prepareCoreSetup(const QString &, const QVariantMap &, const QString &, const QVariantMap &)));
     setPage(SyncPage, syncPage);
     syncRelayPage = new CoreConfigWizardPages::SyncRelayPage(this);
     connect(syncRelayPage, SIGNAL(startOver()), this, SLOT(startOver()));
     setPage(SyncPage, syncPage);
     syncRelayPage = new CoreConfigWizardPages::SyncRelayPage(this);
     connect(syncRelayPage, SIGNAL(startOver()), this, SLOT(startOver()));
@@ -82,14 +87,18 @@ QHash<QString, QVariant> CoreConfigWizard::backends() const
     return _backends;
 }
 
     return _backends;
 }
 
+QHash<QString, QVariant> CoreConfigWizard::authenticators() const
+{
+       return _authenticators;
+}
 
 
-void CoreConfigWizard::prepareCoreSetup(const QString &backend, const QVariantMap &properties)
+void CoreConfigWizard::prepareCoreSetup(const QString &backend, const QVariantMap &properties, const QString &authBackend, const QVariantMap &authProperties)
 {
     // Prevent the user from changing any settings he already specified...
     foreach(int idx, visitedPages())
     page(idx)->setEnabled(false);
 
 {
     // Prevent the user from changing any settings he already specified...
     foreach(int idx, visitedPages())
     page(idx)->setEnabled(false);
 
-    coreConnection()->setupCore(Protocol::SetupData(field("adminUser.user").toString(), field("adminUser.password").toString(), backend, properties));
+    coreConnection()->setupCore(Protocol::SetupData(field("adminUser.user").toString(), field("adminUser.password").toString(), backend, authBackend, properties, authProperties));
 }
 
 
 }
 
 
@@ -175,7 +184,7 @@ AdminUserPage::AdminUserPage(QWidget *parent) : QWizardPage(parent)
 
 int AdminUserPage::nextId() const
 {
 
 int AdminUserPage::nextId() const
 {
-    return CoreConfigWizard::StorageSelectionPage;
+    return CoreConfigWizard::AuthenticationSelectionPage;
 }
 
 
 }
 
 
@@ -185,6 +194,152 @@ bool AdminUserPage::isComplete() const
     return ok;
 }
 
     return ok;
 }
 
+/*** Authentication Selection Page ***/
+
+AuthenticationSelectionPage::AuthenticationSelectionPage(const QHash<QString, QVariant> &backends, QWidget *parent)
+    : QWizardPage(parent),
+    _connectionBox(0),
+    _backends(backends)
+{
+    ui.setupUi(this);
+
+    setTitle(tr("Select Authentication Backend"));
+    setSubTitle(tr("Please select a backend for Quassel Core to use for authenticating users."));
+    setCommitPage(true);
+
+    registerField("authentication.backend", ui.backendList);
+
+    foreach(QString key, _backends.keys()) {
+        ui.backendList->addItem(_backends[key].toMap()["DisplayName"].toString(), key);
+    }
+
+    on_backendList_currentIndexChanged();
+}
+
+
+int AuthenticationSelectionPage::nextId() const
+{
+    return CoreConfigWizard::StorageSelectionPage;
+}
+
+
+QString AuthenticationSelectionPage::selectedBackend() const
+{
+    return ui.backendList->currentText();
+}
+
+
+QVariantMap AuthenticationSelectionPage::connectionProperties() const
+{
+    QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
+
+    QVariantMap properties;
+    QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
+    if (!setupKeys.isEmpty()) {
+        QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
+        foreach(QString key, setupKeys) {
+            QWidget *widget = _connectionBox->findChild<QWidget *>(key);
+            QVariant def;
+            if (defaults.contains(key)) {
+                def = defaults[key];
+            }
+            switch (def.type()) {
+            case QVariant::Int:
+            {
+                QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
+                Q_ASSERT(spinbox);
+                def = QVariant(spinbox->value());
+            }
+            break;
+            default:
+            {
+                QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
+                Q_ASSERT(lineEdit);
+                def = QVariant(lineEdit->text());
+            }
+            }
+            properties[key] = def;
+        }
+    }
+    qDebug() << properties;
+
+//   QVariantMap properties = _backends[backend].toMap()["ConnectionProperties"].toMap();
+//   if(!properties.isEmpty() && _connectionBox) {
+//     QVariantMap::iterator propertyIter = properties.begin();
+//     while(propertyIter != properties.constEnd()) {
+//       QWidget *widget = _connectionBox->findChild<QWidget *>(propertyIter.key());
+//       switch(propertyIter.value().type()) {
+//       case QVariant::Int:
+//      {
+//        QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
+//        Q_ASSERT(spinbox);
+//        propertyIter.value() = QVariant(spinbox->value());
+//      }
+//      break;
+//       default:
+//      {
+//        QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
+//        Q_ASSERT(lineEdit);
+//        propertyIter.value() = QVariant(lineEdit->text());
+//      }
+//       }
+//       propertyIter++;
+//     }
+//   }
+    return properties;
+}
+
+
+void AuthenticationSelectionPage::on_backendList_currentIndexChanged()
+{
+    QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
+    ui.description->setText(_backends[backend].toMap()["Description"].toString());
+
+    if (_connectionBox) {
+        layout()->removeWidget(_connectionBox);
+        _connectionBox->deleteLater();
+        _connectionBox = 0;
+    }
+
+    QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
+    if (!setupKeys.isEmpty()) {
+        QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
+        QGroupBox *propertyBox = new QGroupBox(this);
+        propertyBox->setTitle(tr("Connection Properties"));
+        QFormLayout *formlayout = new QFormLayout;
+
+        foreach(QString key, setupKeys) {
+            QWidget *widget = 0;
+            QVariant def;
+            if (defaults.contains(key)) {
+                def = defaults[key];
+            }
+            switch (def.type()) {
+            case QVariant::Int:
+            {
+                QSpinBox *spinbox = new QSpinBox(propertyBox);
+                spinbox->setMaximum(64000);
+                spinbox->setValue(def.toInt());
+                widget = spinbox;
+            }
+            break;
+            default:
+            {
+                QLineEdit *lineEdit = new QLineEdit(def.toString(), propertyBox);
+                if (key.toLower().contains("password")) {
+                    lineEdit->setEchoMode(QLineEdit::Password);
+                }
+                widget = lineEdit;
+            }
+            }
+            widget->setObjectName(key);
+            formlayout->addRow(key + ":", widget);
+        }
+        propertyBox->setLayout(formlayout);
+        static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, propertyBox);
+        _connectionBox = propertyBox;
+    }
+}
 
 /*** Storage Selection Page ***/
 
 
 /*** Storage Selection Page ***/
 
@@ -355,13 +510,23 @@ void SyncPage::initializePage()
     complete = false;
     hasError = false;
 
     complete = false;
     hasError = false;
 
+       // Fill in sync info about the storage layer. 
     StorageSelectionPage *storagePage = qobject_cast<StorageSelectionPage *>(wizard()->page(CoreConfigWizard::StorageSelectionPage));
     QString backend = storagePage->selectedBackend();
     QVariantMap properties = storagePage->connectionProperties();
     StorageSelectionPage *storagePage = qobject_cast<StorageSelectionPage *>(wizard()->page(CoreConfigWizard::StorageSelectionPage));
     QString backend = storagePage->selectedBackend();
     QVariantMap properties = storagePage->connectionProperties();
-    Q_ASSERT(!backend.isEmpty());
-    ui.user->setText(wizard()->field("adminUser.user").toString());
+       Q_ASSERT(!backend.isEmpty());
     ui.backend->setText(backend);
     ui.backend->setText(backend);
-    emit setupCore(backend, properties);
+    
+       // Fill in synci nfo about the authentication layer.
+       AuthenticationSelectionPage *authPage = qobject_cast<AuthenticationSelectionPage *>(wizard()->page(CoreConfigWizard::AuthenticationSelectionPage));
+       QString authBackend = authPage->selectedBackend();
+    QVariantMap authProperties = authPage->connectionProperties();
+       Q_ASSERT(!authBackend.isEmpty());
+    ui.authBackend->setText(authBackend);
+
+    ui.user->setText(wizard()->field("adminUser.user").toString());
+
+       emit setupCore(backend, properties, authBackend, authProperties);
 }
 
 
 }
 
 
index ba28f2a..60691a7 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "ui_coreconfigwizardintropage.h"
 #include "ui_coreconfigwizardadminuserpage.h"
 
 #include "ui_coreconfigwizardintropage.h"
 #include "ui_coreconfigwizardadminuserpage.h"
+#include "ui_coreconfigwizardauthenticationselectionpage.h"
 #include "ui_coreconfigwizardstorageselectionpage.h"
 #include "ui_coreconfigwizardsyncpage.h"
 
 #include "ui_coreconfigwizardstorageselectionpage.h"
 #include "ui_coreconfigwizardsyncpage.h"
 
@@ -45,6 +46,7 @@ public:
     enum {
         IntroPage,
         AdminUserPage,
     enum {
         IntroPage,
         AdminUserPage,
+        AuthenticationSelectionPage,
         StorageSelectionPage,
         SyncPage,
         SyncRelayPage,
         StorageSelectionPage,
         SyncPage,
         SyncRelayPage,
@@ -52,8 +54,9 @@ public:
         ConclusionPage
     };
 
         ConclusionPage
     };
 
-    CoreConfigWizard(CoreConnection *connection, const QList<QVariant> &backends, QWidget *parent = 0);
+    CoreConfigWizard(CoreConnection *connection, const QList<QVariant> &backends, const QList<QVariant> &authenticators, QWidget *parent = 0);
     QHash<QString, QVariant> backends() const;
     QHash<QString, QVariant> backends() const;
+    QHash<QString, QVariant> authenticators() const;
 
     inline CoreConnection *coreConnection() const { return _connection; }
 
 
     inline CoreConnection *coreConnection() const { return _connection; }
 
@@ -66,13 +69,15 @@ public slots:
     void syncFinished();
 
 private slots:
     void syncFinished();
 
 private slots:
-    void prepareCoreSetup(const QString &backend, const QVariantMap &connectionProperties);
+    void prepareCoreSetup(const QString &backend, const QVariantMap &properties, const QString &authBackend, const QVariantMap &authProperties);
     void coreSetupSuccess();
     void coreSetupFailed(const QString &);
     void startOver();
 
 private:
     QHash<QString, QVariant> _backends;
     void coreSetupSuccess();
     void coreSetupFailed(const QString &);
     void startOver();
 
 private:
     QHash<QString, QVariant> _backends;
+    QHash<QString, QVariant> _authenticators;
+
     CoreConfigWizardPages::SyncPage *syncPage;
     CoreConfigWizardPages::SyncRelayPage *syncRelayPage;
 
     CoreConfigWizardPages::SyncPage *syncPage;
     CoreConfigWizardPages::SyncRelayPage *syncRelayPage;
 
@@ -105,6 +110,24 @@ private:
     Ui::CoreConfigWizardAdminUserPage ui;
 };
 
     Ui::CoreConfigWizardAdminUserPage ui;
 };
 
+// Authentication selection before storage selection.
+class AuthenticationSelectionPage : public QWizardPage
+{
+    Q_OBJECT
+
+public:
+    AuthenticationSelectionPage(const QHash<QString, QVariant> &backends, QWidget *parent = 0);
+    int nextId() const;
+    QString selectedBackend() const;
+    QVariantMap connectionProperties() const;
+    
+private slots:
+    void on_backendList_currentIndexChanged();
+private:
+    Ui::CoreConfigWizardAuthenticationSelectionPage ui;
+    QGroupBox *_connectionBox;
+    QHash<QString, QVariant> _backends;
+};
 
 class StorageSelectionPage : public QWizardPage
 {
 
 class StorageSelectionPage : public QWizardPage
 {
@@ -124,7 +147,6 @@ private:
     QHash<QString, QVariant> _backends;
 };
 
     QHash<QString, QVariant> _backends;
 };
 
-
 class SyncPage : public QWizardPage
 {
     Q_OBJECT
 class SyncPage : public QWizardPage
 {
     Q_OBJECT
@@ -141,7 +163,7 @@ public slots:
     void setComplete(bool);
 
 signals:
     void setComplete(bool);
 
 signals:
-    void setupCore(const QString &backend, const QVariantMap &);
+    void setupCore(const QString &backend, const QVariantMap &, const QString &authenticator, const QVariantMap &);
 
 private:
     Ui::CoreConfigWizardSyncPage ui;
 
 private:
     Ui::CoreConfigWizardSyncPage ui;
index 9e7a70a..f6aa446 100644 (file)
@@ -204,7 +204,7 @@ void MainWin::init()
     connect(GraphicalUi::contextMenuActionProvider(), SIGNAL(showChannelList(NetworkId)), SLOT(showChannelList(NetworkId)));
     connect(GraphicalUi::contextMenuActionProvider(), SIGNAL(showIgnoreList(QString)), SLOT(showIgnoreList(QString)));
 
     connect(GraphicalUi::contextMenuActionProvider(), SIGNAL(showChannelList(NetworkId)), SLOT(showChannelList(NetworkId)));
     connect(GraphicalUi::contextMenuActionProvider(), SIGNAL(showIgnoreList(QString)), SLOT(showIgnoreList(QString)));
 
-    connect(Client::coreConnection(), SIGNAL(startCoreSetup(QVariantList)), SLOT(showCoreConfigWizard(QVariantList)));
+    connect(Client::coreConnection(), SIGNAL(startCoreSetup(QVariantList, QVariantList)), SLOT(showCoreConfigWizard(QVariantList, QVariantList)));
     connect(Client::coreConnection(), SIGNAL(connectionErrorPopup(QString)), SLOT(handleCoreConnectionError(QString)));
     connect(Client::coreConnection(), SIGNAL(userAuthenticationRequired(CoreAccount *, bool *, QString)), SLOT(userAuthenticationRequired(CoreAccount *, bool *, QString)));
     connect(Client::coreConnection(), SIGNAL(handleNoSslInClient(bool *)), SLOT(handleNoSslInClient(bool *)));
     connect(Client::coreConnection(), SIGNAL(connectionErrorPopup(QString)), SLOT(handleCoreConnectionError(QString)));
     connect(Client::coreConnection(), SIGNAL(userAuthenticationRequired(CoreAccount *, bool *, QString)), SLOT(userAuthenticationRequired(CoreAccount *, bool *, QString)));
     connect(Client::coreConnection(), SIGNAL(handleNoSslInClient(bool *)), SLOT(handleNoSslInClient(bool *)));
@@ -1366,9 +1366,9 @@ void MainWin::showCoreConnectionDlg()
 }
 
 
 }
 
 
-void MainWin::showCoreConfigWizard(const QVariantList &backends)
+void MainWin::showCoreConfigWizard(const QVariantList &backends, const QVariantList &authBackends)
 {
 {
-    CoreConfigWizard *wizard = new CoreConfigWizard(Client::coreConnection(), backends, this);
+    CoreConfigWizard *wizard = new CoreConfigWizard(Client::coreConnection(), backends, authBackends, this);
 
     wizard->show();
 }
 
     wizard->show();
 }
index afe099f..5d77136 100644 (file)
@@ -120,7 +120,7 @@ private slots:
     void showAboutDlg();
     void showChannelList(NetworkId netId = NetworkId());
     void showCoreConnectionDlg();
     void showAboutDlg();
     void showChannelList(NetworkId netId = NetworkId());
     void showCoreConnectionDlg();
-    void showCoreConfigWizard(const QVariantList &);
+    void showCoreConfigWizard(const QVariantList &, const QVariantList &);
     void showCoreInfoDlg();
     void showAwayLog();
     void showSettingsDlg();
     void showCoreInfoDlg();
     void showAwayLog();
     void showSettingsDlg();
diff --git a/src/qtui/ui/coreconfigwizardauthenticationselectionpage.ui b/src/qtui/ui/coreconfigwizardauthenticationselectionpage.ui
new file mode 100644 (file)
index 0000000..4d0ed79
--- /dev/null
@@ -0,0 +1,92 @@
+<ui version="4.0" >
+ <class>CoreConfigWizardAuthenticationSelectionPage</class>
+ <widget class="QWidget" name="CoreConfigWizardAuthenticationSelectionPage" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>310</width>
+    <height>168</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" >
+   <item>
+    <layout class="QHBoxLayout" >
+     <item>
+      <widget class="QLabel" name="label" >
+       <property name="text" >
+        <string>Authentication Backend:</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QComboBox" name="backendList" >
+       <property name="sizePolicy" >
+        <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="insertPolicy" >
+        <enum>QComboBox::InsertAtBottom</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer>
+       <property name="orientation" >
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0" >
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="descriptionBox" >
+     <property name="title" >
+      <string>Description</string>
+     </property>
+     <layout class="QVBoxLayout" >
+      <item>
+       <widget class="QLabel" name="description" >
+        <property name="text" >
+         <string>Foobar</string>
+        </property>
+        <property name="alignment" >
+         <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+        </property>
+        <property name="wordWrap" >
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer" >
+     <property name="orientation" >
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0" >
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
index 610c17a..0bd6097 100644 (file)
             </property>
            </widget>
           </item>
             </property>
            </widget>
           </item>
+          <item row="2" column="0" >
+           <widget class="QLabel" name="label_2" >
+            <property name="font" >
+             <font>
+              <weight>75</weight>
+              <bold>true</bold>
+             </font>
+            </property>
+            <property name="text" >
+             <string>Authentication Backend:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="1" >
+           <widget class="QLabel" name="authBackend" >
+            <property name="text" >
+             <string>bar</string>
+            </property>
+           </widget>
+          </item>
          </layout>
         </item>
         <item>
          </layout>
         </item>
         <item>