signon  8.40
default-secrets-storage.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /*
00003  * This file is part of signon
00004  *
00005  * Copyright (C) 2011 Canonical Ltd.
00006  *
00007  * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public License
00011  * version 2.1 as published by the Free Software Foundation.
00012  *
00013  * This library is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00021  * 02110-1301 USA
00022  */
00023 
00024 #include "default-secrets-storage.h"
00025 #include "signond-common.h"
00026 
00027 #define RETURN_IF_NOT_OPEN(retval) \
00028     if (!isOpen()) { \
00029         TRACE() << "Secrets DB is not available"; \
00030         SignOn::CredentialsDBError error(QLatin1String("Not open"), \
00031                                          SignOn::CredentialsDBError::NotOpen); \
00032         setLastError(error); return retval; \
00033     }
00034 
00035 #define S(s) QLatin1String(s)
00036 
00037 using namespace SignonDaemonNS;
00038 
00039 bool SecretsDB::createTables()
00040 {
00041     QStringList createTableQuery = QStringList()
00042         <<  QString::fromLatin1(
00043             "CREATE TABLE CREDENTIALS"
00044             "(id INTEGER NOT NULL UNIQUE,"
00045             "username TEXT,"
00046             "password TEXT,"
00047             "PRIMARY KEY (id))")
00048         <<  QString::fromLatin1(
00049             "CREATE TABLE STORE"
00050             "(identity_id INTEGER,"
00051             "method_id INTEGER,"
00052             "key TEXT,"
00053             "value BLOB,"
00054             "PRIMARY KEY (identity_id, method_id, key))")
00055 
00056         << QString::fromLatin1(
00057             // Cascading Delete
00058             "CREATE TRIGGER tg_delete_credentials "
00059             "BEFORE DELETE ON CREDENTIALS "
00060             "FOR EACH ROW BEGIN "
00061             "    DELETE FROM STORE WHERE STORE.identity_id = OLD.id; "
00062             "END; "
00063         );
00064 
00065    foreach (QString createTable, createTableQuery) {
00066         QSqlQuery query = exec(createTable);
00067         if (lastError().isValid()) {
00068             TRACE() << "Error occurred while creating the database.";
00069             return false;
00070         }
00071         query.clear();
00072         commit();
00073     }
00074     return true;
00075 }
00076 
00077 bool SecretsDB::clear()
00078 {
00079     TRACE();
00080 
00081     QStringList clearCommands = QStringList()
00082         << QLatin1String("DELETE FROM CREDENTIALS")
00083         << QLatin1String("DELETE FROM STORE");
00084 
00085     return transactionalExec(clearCommands);
00086 }
00087 
00088 bool SecretsDB::updateCredentials(const quint32 id,
00089                                   const QString &username,
00090                                   const QString &password)
00091 {
00092     if (!startTransaction()) {
00093         TRACE() << "Could not start transaction. Error inserting credentials.";
00094         return false;
00095     }
00096     QSqlQuery query = newQuery();
00097 
00098     TRACE() << "INSERT:" << id;
00099     query.prepare(S("INSERT OR REPLACE INTO CREDENTIALS "
00100                     "(id, username, password) "
00101                     "VALUES(:id, :username, :password)"));
00102 
00103     query.bindValue(S(":id"), id);
00104     query.bindValue(S(":username"), username);
00105     query.bindValue(S(":password"), password);
00106 
00107     exec(query);
00108 
00109     if (errorOccurred()) {
00110         rollback();
00111         TRACE() << "Error occurred while storing crendentials";
00112         return false;
00113     }
00114     return commit();
00115 }
00116 
00117 bool SecretsDB::removeCredentials(const quint32 id)
00118 {
00119     TRACE();
00120 
00121     QStringList queries = QStringList()
00122         << QString::fromLatin1(
00123             "DELETE FROM CREDENTIALS WHERE id = %1").arg(id)
00124         << QString::fromLatin1(
00125             "DELETE FROM STORE WHERE identity_id = %1").arg(id);
00126 
00127     return transactionalExec(queries);
00128 }
00129 
00130 bool SecretsDB::loadCredentials(const quint32 id,
00131                                 QString &username,
00132                                 QString &password)
00133 {
00134     TRACE();
00135 
00136     QString queryStr =
00137         QString::fromLatin1("SELECT username, password FROM credentials "
00138                             "WHERE id = %1").arg(id);
00139     QSqlQuery query = exec(queryStr);
00140     if (!query.first()) {
00141         TRACE() << "No result or invalid credentials query.";
00142         return false;
00143     }
00144 
00145     username = query.value(0).toString();
00146     password = query.value(1).toString();
00147     return true;
00148 }
00149 
00150 QVariantMap SecretsDB::loadData(quint32 id, quint32 method)
00151 {
00152     TRACE();
00153 
00154     QSqlQuery q = newQuery();
00155     q.prepare(S("SELECT key, value "
00156                 "FROM STORE WHERE identity_id = :id AND method_id = :method"));
00157     q.bindValue(S(":id"), id);
00158     q.bindValue(S(":method"), method);
00159     exec(q);
00160     if (errorOccurred())
00161         return QVariantMap();
00162 
00163     QVariantMap result;
00164     while (q.next()) {
00165         QByteArray array;
00166         array = q.value(1).toByteArray();
00167         QDataStream stream(array);
00168         QVariant data;
00169         stream >> data;
00170         result.insert(q.value(0).toString(), data);
00171     }
00172     return result;
00173 }
00174 
00175 bool SecretsDB::storeData(quint32 id, quint32 method, const QVariantMap &data)
00176 {
00177     TRACE();
00178 
00179     if (!startTransaction()) {
00180         TRACE() << "Could not start transaction. Error inserting data.";
00181         return false;
00182     }
00183 
00184     bool allOk = true;
00185     qint32 dataCounter = 0;
00186     if (!(data.keys().empty())) {
00187         QMapIterator<QString, QVariant> it(data);
00188         while (it.hasNext()) {
00189             it.next();
00190 
00191             QByteArray array;
00192             QDataStream stream(&array, QIODevice::WriteOnly);
00193             stream << it.value();
00194 
00195             dataCounter += it.key().size() +array.size();
00196             if (dataCounter >= SSO_MAX_TOKEN_STORAGE) {
00197                 BLAME() << "storing data max size exceeded";
00198                 allOk = false;
00199                 break;
00200             }
00201             /* Key/value insert/replace/delete */
00202             QSqlQuery query = newQuery();
00203             if (it.value().isValid() && !it.value().isNull()) {
00204                 TRACE() << "insert";
00205                 query.prepare(S(
00206                     "INSERT OR REPLACE INTO STORE "
00207                     "(identity_id, method_id, key, value) "
00208                     "VALUES(:id, :method, :key, :value)"));
00209                 query.bindValue(S(":value"), array);
00210             } else {
00211                 TRACE() << "remove";
00212                 query.prepare(S(
00213                     "DELETE FROM STORE WHERE identity_id = :id "
00214                     "AND method_id = :method "
00215                     "AND key = :key"));
00216 
00217             }
00218             query.bindValue(S(":id"), id);
00219             query.bindValue(S(":method"), method);
00220             query.bindValue(S(":key"), it.key());
00221             exec(query);
00222             if (errorOccurred()) {
00223                 allOk = false;
00224                 break;
00225             }
00226         }
00227     }
00228 
00229     if (allOk && commit()) {
00230         TRACE() << "Data insertion ok.";
00231         return true;
00232     }
00233     rollback();
00234     TRACE() << "Data insertion failed.";
00235     return false;
00236 }
00237 
00238 bool SecretsDB::removeData(quint32 id, quint32 method)
00239 {
00240     TRACE();
00241 
00242     if (!startTransaction()) {
00243         TRACE() << "Could not start transaction. Error removing data.";
00244         return false;
00245     }
00246 
00247     QSqlQuery q = newQuery();
00248     if (method == 0) {
00249         q.prepare(S("DELETE FROM STORE WHERE identity_id = :id"));
00250     } else {
00251         q.prepare(S("DELETE FROM STORE WHERE identity_id = :id "
00252                     "AND method_id = :method"));
00253         q.bindValue(S(":method"), method);
00254     }
00255     q.bindValue(S(":id"), id);
00256     exec(q);
00257     if (!errorOccurred() && commit()) {
00258         TRACE() << "Data removal ok.";
00259         return true;
00260     } else {
00261         rollback();
00262         TRACE() << "Data removal failed.";
00263         return false;
00264     }
00265 }
00266 
00267 DefaultSecretsStorage::DefaultSecretsStorage(QObject *parent):
00268     AbstractSecretsStorage(parent)
00269 {
00270 }
00271 
00272 DefaultSecretsStorage::~DefaultSecretsStorage()
00273 {
00274     close();
00275 }
00276 
00277 bool DefaultSecretsStorage::initialize(const QVariantMap &configuration)
00278 {
00279     if (isOpen()) {
00280         TRACE() << "Initializing open DB; closing first...";
00281         close();
00282     }
00283 
00284     QString name = configuration.value(QLatin1String("name")).toString();
00285 
00286     m_secretsDB = new SecretsDB(name);
00287     if (!m_secretsDB->init()) {
00288         setLastError(m_secretsDB->lastError());
00289         delete m_secretsDB;
00290         m_secretsDB = 0;
00291         return false;
00292     }
00293 
00294     setIsOpen(true);
00295     return true;
00296 }
00297 
00298 bool DefaultSecretsStorage::close()
00299 {
00300     if (m_secretsDB != 0) {
00301         QString connectionName = m_secretsDB->connectionName();
00302         delete m_secretsDB;
00303         QSqlDatabase::removeDatabase(connectionName);
00304         m_secretsDB = 0;
00305     }
00306     return AbstractSecretsStorage::close();
00307 }
00308 
00309 bool DefaultSecretsStorage::clear()
00310 {
00311     RETURN_IF_NOT_OPEN(false);
00312 
00313     return m_secretsDB->clear();
00314 }
00315 
00316 bool DefaultSecretsStorage::updateCredentials(const quint32 id,
00317                                               const QString &username,
00318                                               const QString &password)
00319 {
00320     RETURN_IF_NOT_OPEN(false);
00321 
00322     return m_secretsDB->updateCredentials(id, username, password);
00323 }
00324 
00325 bool DefaultSecretsStorage::removeCredentials(const quint32 id)
00326 {
00327     RETURN_IF_NOT_OPEN(false);
00328 
00329     return m_secretsDB->removeCredentials(id);
00330 }
00331 
00332 bool DefaultSecretsStorage::loadCredentials(const quint32 id,
00333                                             QString &username,
00334                                             QString &password)
00335 {
00336     RETURN_IF_NOT_OPEN(false);
00337 
00338     return m_secretsDB->loadCredentials(id, username, password);
00339 }
00340 
00341 QVariantMap DefaultSecretsStorage::loadData(quint32 id, quint32 method)
00342 {
00343     RETURN_IF_NOT_OPEN(QVariantMap());
00344 
00345     return m_secretsDB->loadData(id, method);
00346 }
00347 
00348 bool DefaultSecretsStorage::storeData(quint32 id, quint32 method,
00349                                       const QVariantMap &data)
00350 {
00351     RETURN_IF_NOT_OPEN(false);
00352 
00353     return m_secretsDB->storeData(id, method, data);
00354 }
00355 
00356 bool DefaultSecretsStorage::removeData(quint32 id, quint32 method)
00357 {
00358     RETURN_IF_NOT_OPEN(false);
00359 
00360     return m_secretsDB->removeData(id, method);
00361 }