signon
8.58
|
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 /* first, remove existing data */ 00185 QSqlQuery q = newQuery(); 00186 q.prepare(S("DELETE FROM STORE WHERE identity_id = :id " 00187 "AND method_id = :method")); 00188 q.bindValue(S(":id"), id); 00189 q.bindValue(S(":method"), method); 00190 exec(q); 00191 if (errorOccurred()) { 00192 rollback(); 00193 TRACE() << "Data removal failed."; 00194 return false; 00195 } 00196 00197 bool allOk = true; 00198 qint32 dataCounter = 0; 00199 if (!(data.keys().empty())) { 00200 QMapIterator<QString, QVariant> it(data); 00201 while (it.hasNext()) { 00202 it.next(); 00203 00204 QByteArray array; 00205 QDataStream stream(&array, QIODevice::WriteOnly); 00206 stream << it.value(); 00207 00208 dataCounter += it.key().size() +array.size(); 00209 if (dataCounter >= SSO_MAX_TOKEN_STORAGE) { 00210 BLAME() << "storing data max size exceeded"; 00211 allOk = false; 00212 break; 00213 } 00214 /* Key/value insert/replace/delete */ 00215 QSqlQuery query = newQuery(); 00216 if (!it.value().isValid() || it.value().isNull()) { 00217 continue; 00218 } 00219 TRACE() << "insert"; 00220 query.prepare(S( 00221 "INSERT OR REPLACE INTO STORE " 00222 "(identity_id, method_id, key, value) " 00223 "VALUES(:id, :method, :key, :value)")); 00224 query.bindValue(S(":value"), array); 00225 query.bindValue(S(":id"), id); 00226 query.bindValue(S(":method"), method); 00227 query.bindValue(S(":key"), it.key()); 00228 exec(query); 00229 if (errorOccurred()) { 00230 allOk = false; 00231 break; 00232 } 00233 } 00234 } 00235 00236 if (allOk && commit()) { 00237 TRACE() << "Data insertion ok."; 00238 return true; 00239 } 00240 rollback(); 00241 TRACE() << "Data insertion failed."; 00242 return false; 00243 } 00244 00245 bool SecretsDB::removeData(quint32 id, quint32 method) 00246 { 00247 TRACE(); 00248 00249 if (!startTransaction()) { 00250 TRACE() << "Could not start transaction. Error removing data."; 00251 return false; 00252 } 00253 00254 QSqlQuery q = newQuery(); 00255 if (method == 0) { 00256 q.prepare(S("DELETE FROM STORE WHERE identity_id = :id")); 00257 } else { 00258 q.prepare(S("DELETE FROM STORE WHERE identity_id = :id " 00259 "AND method_id = :method")); 00260 q.bindValue(S(":method"), method); 00261 } 00262 q.bindValue(S(":id"), id); 00263 exec(q); 00264 if (!errorOccurred() && commit()) { 00265 TRACE() << "Data removal ok."; 00266 return true; 00267 } else { 00268 rollback(); 00269 TRACE() << "Data removal failed."; 00270 return false; 00271 } 00272 } 00273 00274 DefaultSecretsStorage::DefaultSecretsStorage(QObject *parent): 00275 AbstractSecretsStorage(parent), 00276 m_secretsDB(0) 00277 { 00278 } 00279 00280 DefaultSecretsStorage::~DefaultSecretsStorage() 00281 { 00282 close(); 00283 } 00284 00285 bool DefaultSecretsStorage::initialize(const QVariantMap &configuration) 00286 { 00287 if (isOpen()) { 00288 TRACE() << "Initializing open DB; closing first..."; 00289 close(); 00290 } 00291 00292 QString name; // force deep copy / detach 00293 name.append(configuration.value(QLatin1String("name")).toString()); 00294 00295 m_secretsDB = new SecretsDB(name); 00296 if (!m_secretsDB->init()) { 00297 setLastError(m_secretsDB->lastError()); 00298 delete m_secretsDB; 00299 m_secretsDB = 0; 00300 return false; 00301 } 00302 00303 m_secretsDBConnectionName.clear(); 00304 m_secretsDBConnectionName.append(m_secretsDB->connectionName()); 00305 setIsOpen(true); 00306 return true; 00307 } 00308 00309 bool DefaultSecretsStorage::close() 00310 { 00311 if (m_secretsDB != 0) { 00312 delete m_secretsDB; 00313 QSqlDatabase::removeDatabase(m_secretsDBConnectionName); 00314 m_secretsDB = 0; 00315 } 00316 return AbstractSecretsStorage::close(); 00317 } 00318 00319 bool DefaultSecretsStorage::clear() 00320 { 00321 RETURN_IF_NOT_OPEN(false); 00322 00323 return m_secretsDB->clear(); 00324 } 00325 00326 bool DefaultSecretsStorage::updateCredentials(const quint32 id, 00327 const QString &username, 00328 const QString &password) 00329 { 00330 RETURN_IF_NOT_OPEN(false); 00331 00332 return m_secretsDB->updateCredentials(id, username, password); 00333 } 00334 00335 bool DefaultSecretsStorage::removeCredentials(const quint32 id) 00336 { 00337 RETURN_IF_NOT_OPEN(false); 00338 00339 return m_secretsDB->removeCredentials(id); 00340 } 00341 00342 bool DefaultSecretsStorage::loadCredentials(const quint32 id, 00343 QString &username, 00344 QString &password) 00345 { 00346 RETURN_IF_NOT_OPEN(false); 00347 00348 return m_secretsDB->loadCredentials(id, username, password); 00349 } 00350 00351 QVariantMap DefaultSecretsStorage::loadData(quint32 id, quint32 method) 00352 { 00353 RETURN_IF_NOT_OPEN(QVariantMap()); 00354 00355 return m_secretsDB->loadData(id, method); 00356 } 00357 00358 bool DefaultSecretsStorage::storeData(quint32 id, quint32 method, 00359 const QVariantMap &data) 00360 { 00361 RETURN_IF_NOT_OPEN(false); 00362 00363 return m_secretsDB->storeData(id, method, data); 00364 } 00365 00366 bool DefaultSecretsStorage::removeData(quint32 id, quint32 method) 00367 { 00368 RETURN_IF_NOT_OPEN(false); 00369 00370 return m_secretsDB->removeData(id, method); 00371 }