}
registerStorageBackends();
- registerAuthenticatorBackends();
-
+ registerAuthenticators();
+
connect(&_storageSyncTimer, SIGNAL(timeout()), this, SLOT(syncStorage()));
_storageSyncTimer.start(10 * 60 * 1000); // 10 minutes
}
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"));
+ // 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("Authenticator").toString(), authSettings.value("ConnectionProperties").toMap());
+
+ if (Quassel::isOptionSet("select-backend") || Quassel::isOptionSet("select-authenticator")) {
+ if (Quassel::isOptionSet("select-backend")) {
+ selectBackend(Quassel::optionValue("select-backend"));
+ }
+ if (Quassel::isOptionSet("select-authenticator")) {
+ selectAuthenticator(Quassel::optionValue("select-authenticator"));
+ }
exit(0);
}
-
- // TODO: add --select-authenticator command line option and code.
if (!_configured) {
if (!_storageBackends.count()) {
}
qDeleteAll(_sessions);
qDeleteAll(_storageBackends);
+ qDeleteAll(_authenticators);
}
/*** Core Setup ***/
-QString Core::setup(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData, const QString &authBackend, const QVariantMap &authSetupData)
+QString Core::setup(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData, const QString &authenticator, const QVariantMap &authSetupData)
{
- return instance()->setupCore(adminUser, adminPassword, backend, setupData, authBackend, authSetupData);
+ return instance()->setupCore(adminUser, adminPassword, backend, setupData, authenticator, authSetupData);
}
-QString Core::setupCore(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData, const QString &authBackend, const QVariantMap &authSetupData)
+QString Core::setupCore(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData, const QString &authenticator, const QVariantMap &authSetupData)
{
if (_configured)
return tr("Core is already configured! Not configuring again...");
return tr("Could not setup storage!");
}
+ quInfo() << "Selected authenticator: " << authenticator;
+ if (!(_configured = initAuthenticator(authenticator, authSetupData, true)))
+ {
+ return tr("Could not setup authenticator!");
+ }
+
if (!saveBackendSettings(backend, setupData)) {
return tr("Could not save backend settings, probably a permission problem.");
}
- saveAuthBackendSettings(authBackend, authSetupData);
+ saveAuthenticatorSettings(authenticator, authSetupData);
quInfo() << qPrintable(tr("Creating admin user..."));
_storage->addUser(adminUser, adminPassword);
// Authentication handling, now independent from storage.
// Register and unregister authenticators.
-void Core::registerAuthenticatorBackends()
+void Core::registerAuthenticators()
{
// Register new authentication backends here!
- registerAuthenticatorBackend(new SqlAuthenticator(this));
+ registerAuthenticator(new SqlAuthenticator(this));
#ifdef HAVE_LDAP
- registerAuthenticatorBackend(new LdapAuthenticator(this));
+ registerAuthenticator(new LdapAuthenticator(this));
#endif
-
+
}
-bool Core::registerAuthenticatorBackend(Authenticator *authenticator)
+bool Core::registerAuthenticator(Authenticator *authenticator)
{
- if (authenticator->isAvailable())
- {
- _authenticatorBackends[authenticator->displayName()] = authenticator;
- return true;
- } else {
- authenticator->deleteLater();
- return false;
- }
+ if (authenticator->isAvailable())
+ {
+ _authenticators[authenticator->backendId()] = authenticator;
+ return true;
+ } else {
+ authenticator->deleteLater();
+ return false;
+ }
}
-void Core::unregisterAuthenticatorBackends()
+void Core::unregisterAuthenticators()
{
- foreach(Authenticator* a, _authenticatorBackends.values())
- {
- a->deleteLater();
- }
- _authenticatorBackends.clear();
+ foreach(Authenticator* a, _authenticators.values())
+ {
+ a->deleteLater();
+ }
+ _authenticators.clear();
}
-void Core::unregisterAuthenticatorBackend(Authenticator *backend)
+void Core::unregisterAuthenticator(Authenticator *backend)
{
- _authenticatorBackends.remove(backend->displayName());
- backend->deleteLater();
+ _authenticators.remove(backend->backendId());
+ backend->deleteLater();
}
// old db settings:
return true;
}
-// XXX: TODO: Apparently, this is legacy?
+// FIXME: Apparently, this is the legacy way of initting storage backends?
+// If there's a not-legacy way, it should be used here
bool Core::initAuthenticator(const QString &backend, const QVariantMap &settings, bool setup)
{
_authenticator = 0;
-
+
if (backend.isEmpty()) {
- return false;
+ return false;
}
-
+
Authenticator *authenticator = 0;
- if (_authenticatorBackends.contains(backend)) {
- authenticator = _authenticatorBackends[backend];
+ if (_authenticators.contains(backend)) {
+ authenticator = _authenticators[backend];
}
else {
qCritical() << "Selected auth backend is not available:" << backend;
exit(EXIT_FAILURE);
case Authenticator::IsReady:
// delete all other backends
- _authenticatorBackends.remove(backend);
- unregisterAuthenticatorBackends();
+ _authenticators.remove(backend);
+ unregisterAuthenticators();
}
_authenticator = authenticator;
- return true;
+ return true;
}
void Core::syncStorage()
QVariantList Core::authenticatorInfo()
{
QVariantList backends;
- foreach(const Authenticator *backend, instance()->_authenticatorBackends.values()) {
+ foreach(const Authenticator *backend, instance()->_authenticators.values()) {
QVariantMap v;
- v["DisplayName"] = backend->displayName();
+ v["DisplayName"] = backend->backendId();
v["Description"] = backend->description();
v["SetupKeys"] = backend->setupKeys();
v["SetupDefaults"] = backend->setupDefaults();
return true;
}
+// TODO: I am not sure if this function is implemented correctly.
+// There is currently no concept of migraiton between auth backends.
+bool Core::selectAuthenticator(const QString &backend)
+{
+ // Register all authentication backends.
+ registerAuthenticators();
+ if (!_authenticators.contains(backend)) {
+ qWarning() << qPrintable(QString("Core::selectAuthenticator(): unsupported backend: %1").arg(backend));
+ qWarning() << " supported backends are:" << qPrintable(QStringList(_authenticators.keys()).join(", "));
+ return false;
+ }
+
+ Authenticator *authenticator = _authenticators[backend];
+ QVariantMap settings = promptForSettings(authenticator);
+
+ Authenticator::State state = authenticator->init(settings);
+ switch (state) {
+ case Authenticator::IsReady:
+ saveAuthenticatorSettings(backend, settings);
+ qWarning() << "Switched auth backend to:" << qPrintable(backend);
+// qWarning() << "Auth backend already initialized. Skipping Migration";
+ return true;
+ case Authenticator::NotAvailable:
+ qCritical() << "Auth backend is not available:" << qPrintable(backend);
+ return false;
+ case Authenticator::NeedsSetup:
+ if (!authenticator->setup(settings)) {
+ qWarning() << qPrintable(QString("Core::selectAuthenticator(): unable to setup authenticator: %1").arg(backend));
+ return false;
+ }
+
+ if (authenticator->init(settings) != Authenticator::IsReady) {
+ qWarning() << qPrintable(QString("Core::migrateBackend(): unable to initialize authenticator: %1").arg(backend));
+ return false;
+ }
+
+ saveAuthenticatorSettings(backend, settings);
+ qWarning() << "Switched auth backend to:" << qPrintable(backend);
+ }
+
+ _authenticator = authenticator;
+ return true;
+}
+
bool Core::createUser()
{
return false;
}
+ if (!canChangeUserPassword(userId))
+ {
+ out << "User " << username << " is configured through an auth provider that has forbidden manual password changing." << endl;
+ return false;
+ }
+
out << "Change password for user: " << username << endl;
disableStdInEcho();
if (!isConfigured() || !userId.isValid())
return false;
+ if (!canChangeUserPassword(userId))
+ return false;
+
return instance()->_storage->updateUser(userId, password);
}
+// TODO: this code isn't currently 100% optimal because the core
+// doesn't know it can have multiple auth providers configured (there aren't
+// multiple auth providers at the moment anyway) and we have hardcoded the
+// Database provider to be always allowed.
+bool Core::canChangeUserPassword(UserId userId)
+{
+ QString authProvider = instance()->_storage->getUserAuthenticator(userId);
+ if (authProvider != "Database")
+ {
+ if (authProvider != instance()->_authenticator->backendId()) {
+ return false;
+ } else if (instance()->_authenticator->canChangePassword()) {
+ return false;
+ }
+ }
+ return true;
+}
AbstractSqlMigrationReader *Core::getMigrationReader(Storage *storage)
{
return s.sync();
}
-void Core::saveAuthBackendSettings(const QString &backend, const QVariantMap &settings)
+void Core::saveAuthenticatorSettings(const QString &backend, const QVariantMap &settings)
{
QVariantMap dbsettings;
- dbsettings["AuthBackend"] = backend;
+ dbsettings["Authenticator"] = backend;
dbsettings["ConnectionProperties"] = settings;
CoreSettings().setAuthSettings(dbsettings);
}
-
-QVariantMap Core::promptForSettings(const Storage *storage)
+// Generic version of promptForSettings that doesn't care what *type* of
+// backend it runs over.
+QVariantMap Core::promptForSettings(QStringList keys, QVariantMap defaults)
{
QVariantMap settings;
- QStringList keys = storage->setupKeys();
if (keys.isEmpty())
return settings;
QTextStream in(stdin);
out << "Default values are in brackets" << endl;
- QVariantMap defaults = storage->setupDefaults();
QString value;
foreach(QString key, keys) {
QVariant val;
return settings;
}
+// Since an auth and storage backend work basically the same way,
+// use polymorphism here on this routine.
+QVariantMap Core::promptForSettings(const Storage *storage)
+{
+ QStringList keys = storage->setupKeys();
+ QVariantMap defaults = storage->setupDefaults();
+ return Core::promptForSettings(keys, defaults);
+
+}
+
+QVariantMap Core::promptForSettings(const Authenticator *authenticator)
+{
+ QStringList keys = authenticator->setupKeys();
+ QVariantMap defaults = authenticator->setupDefaults();
+ return Core::promptForSettings(keys, defaults);
+}
+
#ifdef Q_OS_WIN
void Core::stdInEcho(bool on)