|
signon
8.40
|
00001 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 00002 /* 00003 * This file is part of signon 00004 * 00005 * Copyright (C) 2009-2010 Nokia Corporation. 00006 * 00007 * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com> 00008 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> 00009 * 00010 * This library is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU Lesser General Public License 00012 * version 2.1 as published by the Free Software Foundation. 00013 * 00014 * This library is distributed in the hope that it will be useful, but 00015 * WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00022 * 02110-1301 USA 00023 */ 00024 00025 #include "credentialsdb.h" 00026 #include "signond-common.h" 00027 00028 #define INIT_ERROR() ErrorMonitor errorMonitor(this) 00029 #define RETURN_IF_NO_SECRETS_DB(retval) \ 00030 if (!isSecretsDBOpen()) { \ 00031 TRACE() << "Secrets DB is not available"; \ 00032 _lastError = noSecretsDB; return retval; \ 00033 } 00034 00035 #define S(s) QLatin1String(s) 00036 00037 namespace SignonDaemonNS { 00038 00039 static const QString driver = QLatin1String("QSQLITE"); 00040 00041 SqlDatabase::SqlDatabase(const QString &databaseName, 00042 const QString &connectionName, 00043 int version): 00044 m_lastError(SignOn::CredentialsDBError()), 00045 m_version(version), 00046 m_database(QSqlDatabase::addDatabase(driver, connectionName)) 00047 00048 { 00049 TRACE() << "Supported Drivers:" << this->supportedDrivers(); 00050 TRACE() << "DATABASE NAME [" << databaseName << "]"; 00051 00052 m_database.setDatabaseName(databaseName); 00053 } 00054 00055 SqlDatabase::~SqlDatabase() 00056 { 00057 m_database.commit(); 00058 m_database.close(); 00059 } 00060 00061 bool SqlDatabase::init() 00062 { 00063 if (!connect()) 00064 return false; 00065 00066 TRACE() << "Database connection succeeded."; 00067 00068 if (!hasTables()) { 00069 TRACE() << "Creating SQL table structure..."; 00070 if (!createTables()) 00071 return false; 00072 00073 if (!SqlDatabase::updateDB(m_version)) 00074 BLAME() << "Failed to set database version to: " << m_version 00075 << ".This could lead to data loss."; 00076 } else { 00077 TRACE() << "SQL table structure already created..."; 00078 // check the DB version 00079 QSqlQuery q = exec(S("PRAGMA user_version")); 00080 int oldVersion = q.first() ? q.value(0).toInt() : 0; 00081 if (oldVersion < m_version) 00082 updateDB(oldVersion); 00083 } 00084 00085 return true; 00086 } 00087 00088 bool SqlDatabase::updateDB(int version) 00089 { 00090 TRACE() << "Update DB from version " << version << " to " << m_version; 00091 exec(QString::fromLatin1("PRAGMA user_version = %1").arg(m_version)); 00092 return true; 00093 } 00094 00095 bool SqlDatabase::connect() 00096 { 00097 if (!m_database.open()) { 00098 TRACE() << "Could not open database connection.\n"; 00099 setLastError(m_database.lastError()); 00100 return false; 00101 } 00102 return true; 00103 } 00104 00105 void SqlDatabase::disconnect() 00106 { 00107 m_database.close(); 00108 } 00109 00110 bool SqlDatabase::startTransaction() 00111 { 00112 return m_database.transaction(); 00113 } 00114 00115 bool SqlDatabase::commit() 00116 { 00117 return m_database.commit(); 00118 } 00119 00120 void SqlDatabase::rollback() 00121 { 00122 if (!m_database.rollback()) 00123 TRACE() << "Rollback failed, db data integrity could be compromised."; 00124 } 00125 00126 QSqlQuery SqlDatabase::exec(const QString &queryStr) 00127 { 00128 QSqlQuery query(QString(), m_database); 00129 00130 if (!query.prepare(queryStr)) 00131 TRACE() << "Query prepare warning: " << query.lastQuery(); 00132 00133 if (!query.exec()) { 00134 TRACE() << "Query exec error: " << query.lastQuery(); 00135 setLastError(query.lastError()); 00136 TRACE() << errorInfo(query.lastError()); 00137 } else 00138 m_lastError.clear(); 00139 00140 return query; 00141 } 00142 00143 QSqlQuery SqlDatabase::exec(QSqlQuery &query) 00144 { 00145 00146 if (!query.exec()) { 00147 TRACE() << "Query exec error: " << query.lastQuery(); 00148 setLastError(query.lastError()); 00149 TRACE() << errorInfo(query.lastError()); 00150 } else 00151 m_lastError.clear(); 00152 00153 return query; 00154 } 00155 00156 00157 bool SqlDatabase::transactionalExec(const QStringList &queryList) 00158 { 00159 if (!startTransaction()) { 00160 setLastError(m_database.lastError()); 00161 TRACE() << "Could not start transaction"; 00162 return false; 00163 } 00164 00165 bool allOk = true; 00166 foreach (QString queryStr, queryList) { 00167 TRACE() << QString::fromLatin1("TRANSACT Query [%1]").arg(queryStr); 00168 QSqlQuery query = exec(queryStr); 00169 00170 if (errorOccurred()) { 00171 allOk = false; 00172 break; 00173 } 00174 } 00175 00176 if (allOk && commit()) { 00177 TRACE() << "Commit SUCCEEDED."; 00178 return true; 00179 } else { 00180 rollback(); 00181 } 00182 00183 TRACE() << "Transactional exec FAILED!"; 00184 return false; 00185 } 00186 00187 SignOn::CredentialsDBError SqlDatabase::lastError() const 00188 { 00189 return m_lastError; 00190 } 00191 00192 void SqlDatabase::setLastError(const QSqlError &sqlError) 00193 { 00194 if (sqlError.isValid()) { 00195 if (sqlError.type() == QSqlError::ConnectionError) { 00196 m_lastError.setType(SignOn::CredentialsDBError::ConnectionError); 00197 } else { 00198 m_lastError.setType(SignOn::CredentialsDBError::StatementError); 00199 } 00200 m_lastError.setText(sqlError.text()); 00201 } else { 00202 m_lastError.clear(); 00203 } 00204 } 00205 00206 QString SqlDatabase::errorInfo(const QSqlError &error) 00207 { 00208 if (!error.isValid()) 00209 return QLatin1String("SQL Error invalid."); 00210 00211 QString text; 00212 QTextStream stream(&text); 00213 stream << "SQL error description:"; 00214 stream << "\n\tType: "; 00215 00216 const char *errType; 00217 switch (error.type()) { 00218 case QSqlError::NoError: errType = "NoError"; break; 00219 case QSqlError::ConnectionError: errType = "ConnectionError"; break; 00220 case QSqlError::StatementError: errType = "StatementError"; break; 00221 case QSqlError::TransactionError: errType = "TransactionError"; break; 00222 case QSqlError::UnknownError: 00223 /* fall trough */ 00224 default: errType = "UnknownError"; 00225 } 00226 stream << errType; 00227 stream << "\n\tDatabase text: " << error.databaseText(); 00228 stream << "\n\tDriver text: " << error.driverText(); 00229 stream << "\n\tNumber: " << error.number(); 00230 00231 return text; 00232 } 00233 00234 QStringList SqlDatabase::queryList(const QString &query_str) 00235 { 00236 QSqlQuery query(QString(), m_database); 00237 if (!query.prepare(query_str)) 00238 TRACE() << "Query prepare warning: " << query.lastQuery(); 00239 return queryList(query); 00240 } 00241 00242 QStringList SqlDatabase::queryList(QSqlQuery &q) 00243 { 00244 QStringList list; 00245 QSqlQuery query = exec(q); 00246 if (errorOccurred()) return list; 00247 while (query.next()) { 00248 list.append(query.value(0).toString()); 00249 } 00250 query.clear(); 00251 return list; 00252 } 00253 00254 QStringList MetaDataDB::tableUpdates2() 00255 { 00256 QStringList tableUpdates = QStringList() 00257 << QString::fromLatin1( 00258 "CREATE TABLE OWNER" 00259 "(rowid INTEGER PRIMARY KEY AUTOINCREMENT," 00260 "identity_id INTEGER CONSTRAINT fk_identity_id REFERENCES CREDENTIALS(id) ON DELETE CASCADE," 00261 "token_id INTEGER CONSTRAINT fk_token_id REFERENCES TOKENS(id) ON DELETE CASCADE)") 00262 //added triggers for OWNER 00263 << QString::fromLatin1( 00264 // Foreign Key Preventing insert 00265 "CREATE TRIGGER fki_OWNER_token_id_TOKENS_id " 00266 "BEFORE INSERT ON [OWNER] " 00267 "FOR EACH ROW BEGIN " 00268 " SELECT RAISE(ROLLBACK, 'insert on table OWNER violates foreign key constraint fki_OWNER_token_id_TOKENS_id') " 00269 " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; " 00270 "END; " 00271 ) 00272 << QString::fromLatin1( 00273 // Foreign key preventing update 00274 "CREATE TRIGGER fku_OWNER_token_id_TOKENS_id " 00275 "BEFORE UPDATE ON [OWNER] " 00276 "FOR EACH ROW BEGIN " 00277 " SELECT RAISE(ROLLBACK, 'update on table OWNER violates foreign key constraint fku_OWNER_token_id_TOKENS_id') " 00278 " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; " 00279 "END; " 00280 ) 00281 << QString::fromLatin1( 00282 // Cascading Delete 00283 "CREATE TRIGGER fkdc_OWNER_token_id_TOKENS_id " 00284 "BEFORE DELETE ON TOKENS " 00285 "FOR EACH ROW BEGIN " 00286 " DELETE FROM OWNER WHERE OWNER.token_id = OLD.id; " 00287 "END; " 00288 ); 00289 00290 return tableUpdates; 00291 } 00292 00293 bool MetaDataDB::createTables() 00294 { 00295 /* !!! Foreign keys support seems to be disabled, for the moment... */ 00296 QStringList createTableQuery = QStringList() 00297 << QString::fromLatin1( 00298 "CREATE TABLE CREDENTIALS" 00299 "(id INTEGER PRIMARY KEY AUTOINCREMENT," 00300 "caption TEXT," 00301 "username TEXT," 00302 "flags INTEGER," 00303 "type INTEGER)") 00304 << QString::fromLatin1( 00305 "CREATE TABLE METHODS" 00306 "(id INTEGER PRIMARY KEY AUTOINCREMENT," 00307 "method TEXT UNIQUE)") 00308 << QString::fromLatin1( 00309 "CREATE TABLE MECHANISMS" 00310 "(id INTEGER PRIMARY KEY AUTOINCREMENT," 00311 "mechanism TEXT UNIQUE)") 00312 << QString::fromLatin1( 00313 "CREATE TABLE TOKENS" 00314 "(id INTEGER PRIMARY KEY AUTOINCREMENT," 00315 "token TEXT UNIQUE)") 00316 << QString::fromLatin1( 00317 "CREATE TABLE REALMS" 00318 "(identity_id INTEGER CONSTRAINT fk_identity_id REFERENCES CREDENTIALS(id) ON DELETE CASCADE," 00319 "realm TEXT," 00320 "hostname TEXT," 00321 "PRIMARY KEY (identity_id, realm, hostname))") 00322 << QString::fromLatin1( 00323 "CREATE TABLE ACL" 00324 "(rowid INTEGER PRIMARY KEY AUTOINCREMENT," 00325 "identity_id INTEGER CONSTRAINT fk_identity_id REFERENCES CREDENTIALS(id) ON DELETE CASCADE," 00326 "method_id INTEGER CONSTRAINT fk_method_id REFERENCES METHODS(id) ON DELETE CASCADE," 00327 "mechanism_id INTEGER CONSTRAINT fk_mechanism_id REFERENCES MECHANISMS(id) ON DELETE CASCADE," 00328 "token_id INTEGER CONSTRAINT fk_token_id REFERENCES TOKENS(id) ON DELETE CASCADE)") 00329 << QString::fromLatin1( 00330 "CREATE TABLE REFS" 00331 "(identity_id INTEGER CONSTRAINT fk_identity_id REFERENCES CREDENTIALS(id) ON DELETE CASCADE," 00332 "token_id INTEGER CONSTRAINT fk_token_id REFERENCES TOKENS(id) ON DELETE CASCADE," 00333 "ref TEXT," 00334 "PRIMARY KEY (identity_id, token_id, ref))") 00335 00336 /* 00337 * triggers generated with 00338 * http://www.rcs-comp.com/site/index.php/view/Utilities-SQLite_foreign_key_trigger_generator 00339 */ 00340 //insert triggers to force foreign keys support 00341 << QString::fromLatin1( 00342 // Foreign Key Preventing insert 00343 "CREATE TRIGGER fki_REALMS_identity_id_CREDENTIALS_id " 00344 "BEFORE INSERT ON [REALMS] " 00345 "FOR EACH ROW BEGIN " 00346 " SELECT RAISE(ROLLBACK, 'insert on table REALMS violates foreign key constraint fki_REALMS_identity_id_CREDENTIALS_id') " 00347 " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; " 00348 "END; " 00349 ) 00350 << QString::fromLatin1( 00351 // Foreign key preventing update 00352 "CREATE TRIGGER fku_REALMS_identity_id_CREDENTIALS_id " 00353 "BEFORE UPDATE ON [REALMS] " 00354 "FOR EACH ROW BEGIN " 00355 " SELECT RAISE(ROLLBACK, 'update on table REALMS violates foreign key constraint fku_REALMS_identity_id_CREDENTIALS_id') " 00356 " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; " 00357 "END; " 00358 ) 00359 << QString::fromLatin1( 00360 // Cascading Delete 00361 "CREATE TRIGGER fkdc_REALMS_identity_id_CREDENTIALS_id " 00362 "BEFORE DELETE ON CREDENTIALS " 00363 "FOR EACH ROW BEGIN " 00364 " DELETE FROM REALMS WHERE REALMS.identity_id = OLD.id; " 00365 "END; " 00366 ) 00367 << QString::fromLatin1( 00368 // Foreign Key Preventing insert 00369 "CREATE TRIGGER fki_ACL_identity_id_CREDENTIALS_id " 00370 "BEFORE INSERT ON [ACL] " 00371 "FOR EACH ROW BEGIN " 00372 " SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign key constraint fki_ACL_identity_id_CREDENTIALS_id') " 00373 " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; " 00374 "END;" 00375 ) 00376 << QString::fromLatin1( 00377 // Foreign key preventing update 00378 "CREATE TRIGGER fku_ACL_identity_id_CREDENTIALS_id " 00379 "BEFORE UPDATE ON [ACL] " 00380 "FOR EACH ROW BEGIN " 00381 " SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign key constraint fku_ACL_identity_id_CREDENTIALS_id') " 00382 " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; " 00383 "END; " 00384 ) 00385 << QString::fromLatin1( 00386 // Cascading Delete 00387 "CREATE TRIGGER fkdc_ACL_identity_id_CREDENTIALS_id " 00388 "BEFORE DELETE ON CREDENTIALS " 00389 "FOR EACH ROW BEGIN " 00390 " DELETE FROM ACL WHERE ACL.identity_id = OLD.id; " 00391 "END; " 00392 ) 00393 << QString::fromLatin1( 00394 // Foreign Key Preventing insert 00395 "CREATE TRIGGER fki_ACL_method_id_METHODS_id " 00396 "BEFORE INSERT ON [ACL] " 00397 "FOR EACH ROW BEGIN " 00398 " SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign key constraint fki_ACL_method_id_METHODS_id') " 00399 " WHERE NEW.method_id IS NOT NULL AND (SELECT id FROM METHODS WHERE id = NEW.method_id) IS NULL; " 00400 "END; " 00401 ) 00402 << QString::fromLatin1( 00403 // Foreign key preventing update 00404 "CREATE TRIGGER fku_ACL_method_id_METHODS_id " 00405 "BEFORE UPDATE ON [ACL] " 00406 "FOR EACH ROW BEGIN " 00407 " SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign key constraint fku_ACL_method_id_METHODS_id') " 00408 " WHERE NEW.method_id IS NOT NULL AND (SELECT id FROM METHODS WHERE id = NEW.method_id) IS NULL; " 00409 "END; " 00410 ) 00411 << QString::fromLatin1( 00412 // Cascading Delete 00413 "CREATE TRIGGER fkdc_ACL_method_id_METHODS_id " 00414 "BEFORE DELETE ON METHODS " 00415 "FOR EACH ROW BEGIN " 00416 " DELETE FROM ACL WHERE ACL.method_id = OLD.id; " 00417 "END; " 00418 ) 00419 << QString::fromLatin1( 00420 // Foreign Key Preventing insert 00421 "CREATE TRIGGER fki_ACL_mechanism_id_MECHANISMS_id " 00422 "BEFORE INSERT ON [ACL] " 00423 "FOR EACH ROW BEGIN " 00424 " SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign key constraint fki_ACL_mechanism_id_MECHANISMS_id') " 00425 " WHERE NEW.mechanism_id IS NOT NULL AND (SELECT id FROM MECHANISMS WHERE id = NEW.mechanism_id) IS NULL; " 00426 "END; " 00427 ) 00428 << QString::fromLatin1( 00429 // Foreign key preventing update 00430 "CREATE TRIGGER fku_ACL_mechanism_id_MECHANISMS_id " 00431 "BEFORE UPDATE ON [ACL] " 00432 "FOR EACH ROW BEGIN " 00433 " SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign key constraint fku_ACL_mechanism_id_MECHANISMS_id') " 00434 " WHERE NEW.mechanism_id IS NOT NULL AND (SELECT id FROM MECHANISMS WHERE id = NEW.mechanism_id) IS NULL; " 00435 "END; " 00436 ) 00437 << QString::fromLatin1( 00438 // Cascading Delete 00439 "CREATE TRIGGER fkdc_ACL_mechanism_id_MECHANISMS_id " 00440 "BEFORE DELETE ON MECHANISMS " 00441 "FOR EACH ROW BEGIN " 00442 " DELETE FROM ACL WHERE ACL.mechanism_id = OLD.id; " 00443 "END; " 00444 ) 00445 << QString::fromLatin1( 00446 // Foreign Key Preventing insert 00447 "CREATE TRIGGER fki_ACL_token_id_TOKENS_id " 00448 "BEFORE INSERT ON [ACL] " 00449 "FOR EACH ROW BEGIN " 00450 " SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign key constraint fki_ACL_token_id_TOKENS_id') " 00451 " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; " 00452 "END; " 00453 ) 00454 << QString::fromLatin1( 00455 // Foreign key preventing update 00456 "CREATE TRIGGER fku_ACL_token_id_TOKENS_id " 00457 "BEFORE UPDATE ON [ACL] " 00458 "FOR EACH ROW BEGIN " 00459 " SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign key constraint fku_ACL_token_id_TOKENS_id') " 00460 " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; " 00461 "END; " 00462 ) 00463 << QString::fromLatin1( 00464 // Cascading Delete 00465 "CREATE TRIGGER fkdc_ACL_token_id_TOKENS_id " 00466 "BEFORE DELETE ON TOKENS " 00467 "FOR EACH ROW BEGIN " 00468 " DELETE FROM ACL WHERE ACL.token_id = OLD.id; " 00469 "END; " 00470 ) 00471 << QString::fromLatin1( 00472 // Foreign Key Preventing insert 00473 "CREATE TRIGGER fki_REFS_identity_id_CREDENTIALS_id " 00474 "BEFORE INSERT ON [REFS] " 00475 "FOR EACH ROW BEGIN " 00476 " SELECT RAISE(ROLLBACK, 'insert on table REFS violates foreign key constraint fki_REFS_identity_id_CREDENTIALS_id') " 00477 " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; " 00478 "END; " 00479 ) 00480 << QString::fromLatin1( 00481 // Foreign key preventing update 00482 "CREATE TRIGGER fku_REFS_identity_id_CREDENTIALS_id " 00483 "BEFORE UPDATE ON [REFS] " 00484 "FOR EACH ROW BEGIN " 00485 " SELECT RAISE(ROLLBACK, 'update on table REFS violates foreign key constraint fku_REFS_identity_id_CREDENTIALS_id') " 00486 " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; " 00487 "END; " 00488 ) 00489 << QString::fromLatin1( 00490 // Cascading Delete 00491 "CREATE TRIGGER fkdc_REFS_identity_id_CREDENTIALS_id " 00492 "BEFORE DELETE ON CREDENTIALS " 00493 "FOR EACH ROW BEGIN " 00494 " DELETE FROM REFS WHERE REFS.identity_id = OLD.id; " 00495 "END; " 00496 ) 00497 << QString::fromLatin1( 00498 // Foreign Key Preventing insert 00499 "CREATE TRIGGER fki_REFS_token_id_TOKENS_id " 00500 "BEFORE INSERT ON [REFS] " 00501 "FOR EACH ROW BEGIN " 00502 " SELECT RAISE(ROLLBACK, 'insert on table REFS violates foreign key constraint fki_REFS_token_id_TOKENS_id') " 00503 " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; " 00504 "END; " 00505 ) 00506 << QString::fromLatin1( 00507 // Foreign key preventing update 00508 "CREATE TRIGGER fku_REFS_token_id_TOKENS_id " 00509 "BEFORE UPDATE ON [REFS] " 00510 "FOR EACH ROW BEGIN " 00511 " SELECT RAISE(ROLLBACK, 'update on table REFS violates foreign key constraint fku_REFS_token_id_TOKENS_id') " 00512 " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; " 00513 "END; " 00514 ) 00515 << QString::fromLatin1( 00516 // Cascading Delete 00517 "CREATE TRIGGER fkdc_REFS_token_id_TOKENS_id " 00518 "BEFORE DELETE ON TOKENS " 00519 "FOR EACH ROW BEGIN " 00520 " DELETE FROM REFS WHERE REFS.token_id = OLD.id; " 00521 "END; " 00522 ); 00523 /* 00524 end of generated code 00525 */ 00526 //insert table updates 00527 createTableQuery << tableUpdates2(); 00528 00529 foreach (QString createTable, createTableQuery) { 00530 QSqlQuery query = exec(createTable); 00531 if (lastError().isValid()) { 00532 TRACE() << "Error occurred while creating the database."; 00533 return false; 00534 } 00535 query.clear(); 00536 commit(); 00537 } 00538 TRACE() << "Creation successful"; 00539 00540 return true; 00541 } 00542 00543 bool MetaDataDB::updateDB(int version) 00544 { 00545 if (version == m_version) 00546 return true; 00547 00548 if (version < 1) { 00549 TRACE() << "Upgrading from version < 1 not supported. Clearing DB"; 00550 QString fileName = m_database.databaseName(); 00551 QString connectionName = m_database.connectionName(); 00552 m_database.close(); 00553 QFile::remove(fileName); 00554 m_database = QSqlDatabase(QSqlDatabase::addDatabase(driver, 00555 connectionName)); 00556 m_database.setDatabaseName(fileName); 00557 if (!connect()) 00558 return false; 00559 00560 if (!createTables()) 00561 return false; 00562 } 00563 00564 //convert from 1 to 2 00565 if (version == 1) { 00566 QStringList createTableQuery = tableUpdates2(); 00567 foreach (QString createTable, createTableQuery) { 00568 QSqlQuery query = exec(createTable); 00569 if (lastError().isValid()) { 00570 TRACE() << "Error occurred while inseting new tables."; 00571 return false; 00572 } 00573 query.clear(); 00574 commit(); 00575 } 00576 TRACE() << "Table insert successful"; 00577 00578 //populate owner table from acl 00579 QSqlQuery ownerInsert = exec(S("INSERT OR IGNORE INTO OWNER " 00580 "(identity_id, token_id) " 00581 " SELECT identity_id, token_id FROM ACL")); 00582 if (!commit()){ 00583 BLAME() << "Table copy failed."; 00584 rollback(); 00585 } 00586 00587 } else { 00588 return false; 00589 } 00590 00591 return SqlDatabase::updateDB(version); 00592 } 00593 00594 QStringList MetaDataDB::methods(const quint32 id, const QString &securityToken) 00595 { 00596 QStringList list; 00597 if (securityToken.isEmpty()) { 00598 list = queryList( 00599 QString::fromLatin1("SELECT DISTINCT METHODS.method FROM " 00600 "( ACL JOIN METHODS ON ACL.method_id = METHODS.id ) " 00601 "WHERE ACL.identity_id = '%1'").arg(id) 00602 ); 00603 return list; 00604 } 00605 QSqlQuery q = newQuery(); 00606 q.prepare(S("SELECT DISTINCT METHODS.method FROM " 00607 "( ACL JOIN METHODS ON ACL.method_id = METHODS.id) " 00608 "WHERE ACL.identity_id = :id AND ACL.token_id = " 00609 "(SELECT id FROM TOKENS where token = :token)")); 00610 q.bindValue(S(":id"), id); 00611 q.bindValue(S(":token"), securityToken); 00612 list = queryList(q); 00613 00614 return list; 00615 } 00616 00617 quint32 MetaDataDB::methodId(const QString &method) 00618 { 00619 TRACE() << "method:" << method; 00620 00621 QSqlQuery q = newQuery(); 00622 q.prepare(S("SELECT id FROM METHODS WHERE method = :method")); 00623 q.bindValue(S(":method"), method); 00624 exec(q); 00625 if (!q.first()) { 00626 TRACE() << "No result or invalid method query."; 00627 return 0; 00628 } 00629 00630 return q.value(0).toUInt(); 00631 } 00632 00633 SignonIdentityInfo MetaDataDB::identity(const quint32 id) 00634 { 00635 QString query_str; 00636 00637 query_str = QString::fromLatin1( 00638 "SELECT caption, username, flags, type " 00639 "FROM credentials WHERE id = %1").arg(id); 00640 QSqlQuery query = exec(query_str); 00641 00642 if (!query.first()) { 00643 TRACE() << "No result or invalid credentials query."; 00644 return SignonIdentityInfo(); 00645 } 00646 00647 QString caption = query.value(0).toString(); 00648 QString username = query.value(1).toString(); 00649 int flags = query.value(2).toInt(); 00650 bool savePassword = flags & RememberPassword; 00651 bool validated = flags & Validated; 00652 bool isUserNameSecret = flags & UserNameIsSecret; 00653 if (isUserNameSecret) username = QString(); 00654 int type = query.value(3).toInt(); 00655 00656 query.clear(); 00657 QStringList realms = queryList( 00658 QString::fromLatin1("SELECT realm FROM REALMS " 00659 "WHERE identity_id = %1").arg(id)); 00660 00661 QStringList ownerTokens = queryList( 00662 QString::fromLatin1("SELECT token FROM TOKENS " 00663 "WHERE id IN " 00664 "(SELECT token_id FROM OWNER WHERE identity_id = '%1' )") 00665 .arg(id)); 00666 00667 query_str = QString::fromLatin1("SELECT token FROM TOKENS " 00668 "WHERE id IN " 00669 "(SELECT token_id FROM ACL WHERE identity_id = '%1' )") 00670 .arg(id); 00671 query = exec(query_str); 00672 QStringList securityTokens; 00673 while (query.next()) { 00674 securityTokens.append(query.value(0).toString()); 00675 } 00676 query.clear(); 00677 MethodMap methods; 00678 query_str = QString::fromLatin1( 00679 "SELECT DISTINCT ACL.method_id, METHODS.method FROM " 00680 "( ACL JOIN METHODS ON ACL.method_id = METHODS.id ) " 00681 "WHERE ACL.identity_id = '%1'").arg(id); 00682 query = exec(query_str); 00683 while (query.next()) { 00684 QStringList mechanisms = queryList( 00685 QString::fromLatin1("SELECT DISTINCT MECHANISMS.mechanism FROM " 00686 "( MECHANISMS JOIN ACL " 00687 "ON ACL.mechanism_id = MECHANISMS.id ) " 00688 "WHERE ACL.method_id = '%1' AND ACL.identity_id = '%2' ") 00689 .arg(query.value(0).toInt()).arg(id)); 00690 methods.insert(query.value(1).toString(), mechanisms); 00691 } 00692 query.clear(); 00693 00694 int refCount = 0; 00695 //TODO query for refcount 00696 00697 SignonIdentityInfo info = 00698 SignonIdentityInfo(id, username, QString(), savePassword, 00699 caption, methods, realms, securityTokens, 00700 ownerTokens, 00701 type, refCount, validated); 00702 info.setUserNameSecret(isUserNameSecret); 00703 return info; 00704 } 00705 00706 QList<SignonIdentityInfo> MetaDataDB::identities(const QMap<QString, 00707 QString> &filter) 00708 { 00709 TRACE(); 00710 Q_UNUSED(filter) 00711 QList<SignonIdentityInfo> result; 00712 00713 QString queryStr(QString::fromLatin1("SELECT id FROM credentials")); 00714 00715 // TODO - process filtering step here !!! 00716 00717 queryStr += QString::fromLatin1(" ORDER BY id"); 00718 00719 QSqlQuery query = exec(queryStr); 00720 if (errorOccurred()) { 00721 TRACE() << "Error occurred while fetching credentials from database."; 00722 return result; 00723 } 00724 00725 while (query.next()) { 00726 SignonIdentityInfo info = identity(query.value(0).toUInt()); 00727 if (errorOccurred()) 00728 break; 00729 result << info; 00730 } 00731 00732 query.clear(); 00733 return result; 00734 } 00735 00736 quint32 MetaDataDB::updateIdentity(const SignonIdentityInfo &info) 00737 { 00738 if (!startTransaction()) { 00739 TRACE() << "Could not start transaction. Error inserting credentials."; 00740 return 0; 00741 } 00742 00743 quint32 id = updateCredentials(info); 00744 if (id == 0) { 00745 rollback(); 00746 return 0; 00747 } 00748 00749 /* Methods inserts */ 00750 insertMethods(info.methods()); 00751 00752 if (!updateRealms(id, info.realms(), info.isNew())) { 00753 TRACE() << "Error in updating realms"; 00754 rollback(); 00755 return 0; 00756 } 00757 00758 /* Security tokens insert */ 00759 foreach (QString token, info.accessControlList()) { 00760 QSqlQuery tokenInsert = newQuery(); 00761 tokenInsert.prepare(S("INSERT OR IGNORE INTO TOKENS (token) " 00762 "VALUES ( :token )")); 00763 tokenInsert.bindValue(S(":token"), token); 00764 exec(tokenInsert); 00765 } 00766 00767 foreach (QString token, info.ownerList()) { 00768 if (!token.isEmpty()) { 00769 QSqlQuery tokenInsert = newQuery(); 00770 tokenInsert.prepare(S("INSERT OR IGNORE INTO TOKENS (token) " 00771 "VALUES ( :token )")); 00772 tokenInsert.bindValue(S(":token"), token); 00773 exec(tokenInsert); 00774 } 00775 } 00776 00777 if (!info.isNew()) { 00778 //remove acl 00779 QString queryStr = QString::fromLatin1( 00780 "DELETE FROM ACL WHERE " 00781 "identity_id = '%1'") 00782 .arg(info.id()); 00783 QSqlQuery insertQuery = exec(queryStr); 00784 insertQuery.clear(); 00785 //remove owner 00786 queryStr = QString::fromLatin1( 00787 "DELETE FROM OWNER WHERE " 00788 "identity_id = '%1'") 00789 .arg(info.id()); 00790 insertQuery = exec(queryStr); 00791 insertQuery.clear(); 00792 } 00793 00794 /* ACL insert, this will do basically identity level ACL */ 00795 QMapIterator<QString, QStringList> it(info.methods()); 00796 while (it.hasNext()) { 00797 it.next(); 00798 if (!info.accessControlList().isEmpty()) { 00799 foreach (QString token, info.accessControlList()) { 00800 foreach (QString mech, it.value()) { 00801 QSqlQuery aclInsert = newQuery(); 00802 aclInsert.prepare(S("INSERT OR REPLACE INTO ACL " 00803 "(identity_id, method_id, mechanism_id, token_id) " 00804 "VALUES ( :id, " 00805 "( SELECT id FROM METHODS WHERE method = :method )," 00806 "( SELECT id FROM MECHANISMS WHERE mechanism= :mech ), " 00807 "( SELECT id FROM TOKENS WHERE token = :token ))")); 00808 aclInsert.bindValue(S(":id"), id); 00809 aclInsert.bindValue(S(":method"), it.key()); 00810 aclInsert.bindValue(S(":mech"), mech); 00811 aclInsert.bindValue(S(":token"), token); 00812 exec(aclInsert); 00813 } 00814 //insert entires for empty mechs list 00815 if (it.value().isEmpty()) { 00816 QSqlQuery aclInsert = newQuery(); 00817 aclInsert.prepare(S("INSERT OR REPLACE INTO ACL (identity_id, method_id, token_id) " 00818 "VALUES ( :id, " 00819 "( SELECT id FROM METHODS WHERE method = :method )," 00820 "( SELECT id FROM TOKENS WHERE token = :token ))")); 00821 aclInsert.bindValue(S(":id"), id); 00822 aclInsert.bindValue(S(":method"), it.key()); 00823 aclInsert.bindValue(S(":token"), token); 00824 exec(aclInsert); 00825 } 00826 } 00827 } else { 00828 foreach (QString mech, it.value()) { 00829 QSqlQuery aclInsert = newQuery(); 00830 aclInsert.prepare(S("INSERT OR REPLACE INTO ACL " 00831 "(identity_id, method_id, mechanism_id) " 00832 "VALUES ( :id, " 00833 "( SELECT id FROM METHODS WHERE method = :method )," 00834 "( SELECT id FROM MECHANISMS WHERE mechanism= :mech )" 00835 ")")); 00836 aclInsert.bindValue(S(":id"), id); 00837 aclInsert.bindValue(S(":method"), it.key()); 00838 aclInsert.bindValue(S(":mech"), mech); 00839 exec(aclInsert); 00840 } 00841 //insert entires for empty mechs list 00842 if (it.value().isEmpty()) { 00843 QSqlQuery aclInsert = newQuery(); 00844 aclInsert.prepare(S("INSERT OR REPLACE INTO ACL (identity_id, method_id) " 00845 "VALUES ( :id, " 00846 "( SELECT id FROM METHODS WHERE method = :method )" 00847 ")")); 00848 aclInsert.bindValue(S(":id"), id); 00849 aclInsert.bindValue(S(":method"), it.key()); 00850 exec(aclInsert); 00851 } 00852 } 00853 } 00854 //insert acl in case where methods are missing 00855 if (info.methods().isEmpty()) { 00856 foreach (QString token, info.accessControlList()) { 00857 QSqlQuery aclInsert = newQuery(); 00858 aclInsert.prepare(S("INSERT OR REPLACE INTO ACL " 00859 "(identity_id, token_id) " 00860 "VALUES ( :id, " 00861 "( SELECT id FROM TOKENS WHERE token = :token ))")); 00862 aclInsert.bindValue(S(":id"), id); 00863 aclInsert.bindValue(S(":token"), token); 00864 exec(aclInsert); 00865 } 00866 } 00867 00868 //insert owner list 00869 foreach (QString token, info.ownerList()) { 00870 if (!token.isEmpty()) { 00871 QSqlQuery ownerInsert = newQuery(); 00872 ownerInsert.prepare(S("INSERT OR REPLACE INTO OWNER " 00873 "(identity_id, token_id) " 00874 "VALUES ( :id, " 00875 "( SELECT id FROM TOKENS WHERE token = :token ))")); 00876 ownerInsert.bindValue(S(":id"), id); 00877 ownerInsert.bindValue(S(":token"), token); 00878 exec(ownerInsert); 00879 } 00880 } 00881 00882 if (commit()) { 00883 return id; 00884 } else { 00885 rollback(); 00886 TRACE() << "Credentials insertion failed."; 00887 return 0; 00888 } 00889 } 00890 00891 bool MetaDataDB::removeIdentity(const quint32 id) 00892 { 00893 TRACE(); 00894 00895 QStringList queries = QStringList() 00896 << QString::fromLatin1( 00897 "DELETE FROM CREDENTIALS WHERE id = %1").arg(id) 00898 << QString::fromLatin1( 00899 "DELETE FROM ACL WHERE identity_id = %1").arg(id) 00900 << QString::fromLatin1( 00901 "DELETE FROM REALMS WHERE identity_id = %1").arg(id) 00902 << QString::fromLatin1( 00903 "DELETE FROM owner WHERE identity_id = %1").arg(id); 00904 00905 return transactionalExec(queries); 00906 } 00907 00908 bool MetaDataDB::clear() 00909 { 00910 TRACE(); 00911 00912 QStringList clearCommands = QStringList() 00913 << QLatin1String("DELETE FROM CREDENTIALS") 00914 << QLatin1String("DELETE FROM METHODS") 00915 << QLatin1String("DELETE FROM MECHANISMS") 00916 << QLatin1String("DELETE FROM ACL") 00917 << QLatin1String("DELETE FROM REALMS") 00918 << QLatin1String("DELETE FROM TOKENS") 00919 << QLatin1String("DELETE FROM OWNER"); 00920 00921 return transactionalExec(clearCommands); 00922 } 00923 00924 QStringList MetaDataDB::accessControlList(const quint32 identityId) 00925 { 00926 return queryList(QString::fromLatin1("SELECT token FROM TOKENS " 00927 "WHERE id IN " 00928 "(SELECT token_id FROM ACL WHERE identity_id = '%1' )") 00929 .arg(identityId)); 00930 } 00931 00932 QStringList MetaDataDB::ownerList(const quint32 identityId) 00933 { 00934 return queryList(QString::fromLatin1("SELECT token FROM TOKENS " 00935 "WHERE id IN " 00936 "(SELECT token_id FROM OWNER WHERE identity_id = '%1' )") 00937 .arg(identityId)); 00938 } 00939 00940 bool MetaDataDB::addReference(const quint32 id, 00941 const QString &token, 00942 const QString &reference) 00943 { 00944 if (!startTransaction()) { 00945 TRACE() << "Could not start transaction. Error inserting data."; 00946 return false; 00947 } 00948 00949 TRACE() << "Storing:" << id << ", " << token << ", " << reference; 00950 /* Data insert */ 00951 bool allOk = true; 00952 00953 /* Security token insert */ 00954 QSqlQuery tokenInsert = newQuery(); 00955 tokenInsert.prepare(S("INSERT OR IGNORE INTO TOKENS (token) " 00956 "VALUES ( :token )")); 00957 tokenInsert.bindValue(S(":token"), token); 00958 exec(tokenInsert); 00959 if (errorOccurred()) { 00960 allOk = false; 00961 } 00962 00963 QSqlQuery refsInsert = newQuery(); 00964 refsInsert.prepare(S("INSERT OR REPLACE INTO REFS " 00965 "(identity_id, token_id, ref) " 00966 "VALUES ( :id, " 00967 "( SELECT id FROM TOKENS WHERE token = :token )," 00968 ":reference" 00969 ")")); 00970 refsInsert.bindValue(S(":id"), id); 00971 refsInsert.bindValue(S(":token"), token); 00972 refsInsert.bindValue(S(":reference"), reference); 00973 exec(refsInsert); 00974 if (errorOccurred()) { 00975 allOk = false; 00976 } 00977 00978 if (allOk && commit()) { 00979 TRACE() << "Data insertion ok."; 00980 return true; 00981 } 00982 rollback(); 00983 TRACE() << "Data insertion failed."; 00984 return false; 00985 } 00986 00987 bool MetaDataDB::removeReference(const quint32 id, 00988 const QString &token, 00989 const QString &reference) 00990 { 00991 TRACE() << "Removing:" << id << ", " << token << ", " << reference; 00992 //check that there is references 00993 QStringList refs = references(id, token); 00994 if (refs.isEmpty()) 00995 return false; 00996 if (!reference.isNull() && !refs.contains(reference)) 00997 return false; 00998 00999 if (!startTransaction()) { 01000 TRACE() << "Could not start transaction. Error removing data."; 01001 return false; 01002 } 01003 01004 bool allOk = true; 01005 QSqlQuery refsDelete = newQuery(); 01006 01007 if (reference.isEmpty()) { 01008 refsDelete.prepare(S("DELETE FROM REFS " 01009 "WHERE identity_id = :id AND " 01010 "token_id = ( SELECT id FROM TOKENS WHERE token = :token )")); 01011 refsDelete.bindValue(S(":id"), id); 01012 refsDelete.bindValue(S(":token"), token); 01013 } else { 01014 refsDelete.prepare(S("DELETE FROM REFS " 01015 "WHERE identity_id = :id AND " 01016 "token_id = ( SELECT id FROM TOKENS WHERE token = :token ) " 01017 "AND ref = :ref")); 01018 refsDelete.bindValue(S(":id"), id); 01019 refsDelete.bindValue(S(":token"), token); 01020 refsDelete.bindValue(S(":ref"), reference); 01021 } 01022 01023 exec(refsDelete); 01024 if (errorOccurred()) { 01025 allOk = false; 01026 } 01027 01028 if (allOk && commit()) { 01029 TRACE() << "Data delete ok."; 01030 return true; 01031 } 01032 rollback(); 01033 TRACE() << "Data delete failed."; 01034 return false; 01035 } 01036 01037 QStringList MetaDataDB::references(const quint32 id, const QString &token) 01038 { 01039 if (token.isEmpty()) 01040 return queryList(QString::fromLatin1("SELECT ref FROM REFS " 01041 "WHERE identity_id = '%1'") 01042 .arg(id)); 01043 QSqlQuery q = newQuery(); 01044 q.prepare(S("SELECT ref FROM REFS " 01045 "WHERE identity_id = :id AND " 01046 "token_id = (SELECT id FROM TOKENS WHERE token = :token )")); 01047 q.bindValue(S(":id"), id); 01048 q.bindValue(S(":token"), token); 01049 return queryList(q); 01050 } 01051 01052 bool MetaDataDB::insertMethods(QMap<QString, QStringList> methods) 01053 { 01054 bool allOk = true; 01055 01056 if (methods.isEmpty()) return false; 01057 //insert (unique) method names 01058 QMapIterator<QString, QStringList> it(methods); 01059 while (it.hasNext()) { 01060 it.next(); 01061 QSqlQuery methodInsert = newQuery(); 01062 methodInsert.prepare(S("INSERT OR IGNORE INTO METHODS (method) " 01063 "VALUES( :method )")); 01064 methodInsert.bindValue(S(":method"), it.key()); 01065 exec(methodInsert); 01066 if (errorOccurred()) allOk = false; 01067 //insert (unique) mechanism names 01068 foreach (QString mech, it.value()) { 01069 QSqlQuery mechInsert = newQuery(); 01070 mechInsert.prepare(S("INSERT OR IGNORE INTO MECHANISMS (mechanism) " 01071 "VALUES( :mech )")); 01072 mechInsert.bindValue(S(":mech"), mech); 01073 exec(mechInsert); 01074 if (errorOccurred()) allOk = false; 01075 } 01076 } 01077 return allOk; 01078 } 01079 01080 quint32 MetaDataDB::insertMethod(const QString &method, bool *ok) 01081 { 01082 QSqlQuery q = newQuery(); 01083 q.prepare(S("INSERT INTO METHODS (method) VALUES(:method)")); 01084 q.bindValue(S(":method"), method); 01085 exec(q); 01086 01087 if (errorOccurred()) { 01088 if (ok != 0) *ok = false; 01089 return 0; 01090 } 01091 return q.lastInsertId().toUInt(ok); 01092 } 01093 01094 quint32 MetaDataDB::updateCredentials(const SignonIdentityInfo &info) 01095 { 01096 quint32 id; 01097 QSqlQuery q = newQuery(); 01098 01099 int flags = 0; 01100 if (info.validated()) flags |= Validated; 01101 if (info.storePassword()) flags |= RememberPassword; 01102 if (info.isUserNameSecret()) flags |= UserNameIsSecret; 01103 01104 if (!info.isNew()) { 01105 TRACE() << "UPDATE:" << info.id() ; 01106 q.prepare(S("UPDATE CREDENTIALS SET caption = :caption, " 01107 "username = :username, " 01108 "flags = :flags, " 01109 "type = :type WHERE id = :id")); 01110 q.bindValue(S(":id"), info.id()); 01111 } else { 01112 TRACE() << "INSERT:" << info.id(); 01113 q.prepare(S("INSERT INTO CREDENTIALS " 01114 "(caption, username, flags, type) " 01115 "VALUES(:caption, :username, :flags, :type)")); 01116 } 01117 q.bindValue(S(":username"), 01118 info.isUserNameSecret() ? QString() : info.userName()); 01119 q.bindValue(S(":caption"), info.caption()); 01120 q.bindValue(S(":flags"), flags); 01121 q.bindValue(S(":type"), info.type()); 01122 exec(q); 01123 if (errorOccurred()) { 01124 TRACE() << "Error occurred while updating crendentials"; 01125 return 0; 01126 } 01127 01128 if (info.isNew()) { 01129 /* Fetch id of the inserted credentials */ 01130 QVariant idVariant = q.lastInsertId(); 01131 if (!idVariant.isValid()) { 01132 TRACE() << "Error occurred while inserting crendentials"; 01133 return 0; 01134 } 01135 id = idVariant.toUInt(); 01136 } else { 01137 id = info.id() ; 01138 } 01139 01140 return id; 01141 } 01142 01143 bool MetaDataDB::updateRealms(quint32 id, const QStringList &realms, bool isNew) 01144 { 01145 QString queryStr; 01146 01147 if (!isNew) { 01148 //remove realms list 01149 queryStr = QString::fromLatin1( 01150 "DELETE FROM REALMS WHERE identity_id = '%1'") 01151 .arg(id); 01152 exec(queryStr); 01153 } 01154 01155 /* Realms insert */ 01156 QSqlQuery q = newQuery(); 01157 q.prepare(S("INSERT OR IGNORE INTO REALMS (identity_id, realm) " 01158 "VALUES (:id, :realm)")); 01159 foreach (QString realm, realms) { 01160 q.bindValue(S(":id"), id); 01161 q.bindValue(S(":realm"), realm); 01162 exec(q); 01163 if (errorOccurred()) return false; 01164 } 01165 return true; 01166 } 01167 01168 /* Error monitor class */ 01169 01170 CredentialsDB::ErrorMonitor::ErrorMonitor(CredentialsDB *db) 01171 { 01172 db->_lastError.setType(SignOn::CredentialsDBError::NoError); 01173 db->metaDataDB->clearError(); 01174 if (db->secretsStorage != 0) 01175 db->secretsStorage->clearError(); 01176 _db = db; 01177 } 01178 01179 CredentialsDB::ErrorMonitor::~ErrorMonitor() 01180 { 01181 /* If there's an error set on the CredentialsDB, just let it be and return. 01182 * If not, take the error from the SqlDatabase objects, if any. 01183 */ 01184 if (_db->_lastError.isValid()) 01185 return; 01186 01187 if (_db->secretsStorage != 0 && 01188 _db->secretsStorage->lastError().isValid()) { 01189 _db->_lastError = _db->secretsStorage->lastError(); 01190 return; 01191 } 01192 01193 _db->_lastError = _db->metaDataDB->lastError(); 01194 } 01195 01196 /* ------- CredentialsDB implementation ------- */ 01197 01198 CredentialsDB::CredentialsDB(const QString &metaDataDbName, 01199 SignOn::AbstractSecretsStorage *secretsStorage): 01200 secretsStorage(secretsStorage), 01201 metaDataDB(new MetaDataDB(metaDataDbName)) 01202 { 01203 noSecretsDB = SignOn::CredentialsDBError( 01204 QLatin1String("Secrets DB not opened"), 01205 SignOn::CredentialsDBError::ConnectionError); 01206 } 01207 01208 CredentialsDB::~CredentialsDB() 01209 { 01210 TRACE(); 01211 if (metaDataDB) { 01212 QString connectionName = metaDataDB->connectionName(); 01213 delete metaDataDB; 01214 QSqlDatabase::removeDatabase(connectionName); 01215 } 01216 } 01217 01218 bool CredentialsDB::init() 01219 { 01220 return metaDataDB->init(); 01221 } 01222 01223 bool CredentialsDB::openSecretsDB(const QString &secretsDbName) 01224 { 01225 QVariantMap configuration; 01226 configuration.insert(QLatin1String("name"), secretsDbName); 01227 if (!secretsStorage->initialize(configuration)) { 01228 TRACE() << "SecretsStorage initialization failed: " << 01229 secretsStorage->lastError().text(); 01230 return false; 01231 } 01232 01233 return true; 01234 } 01235 01236 bool CredentialsDB::isSecretsDBOpen() 01237 { 01238 return secretsStorage != 0 && secretsStorage->isOpen(); 01239 } 01240 01241 void CredentialsDB::closeSecretsDB() 01242 { 01243 if (secretsStorage != 0) secretsStorage->close(); 01244 } 01245 01246 SignOn::CredentialsDBError CredentialsDB::lastError() const 01247 { 01248 return _lastError; 01249 } 01250 01251 QStringList CredentialsDB::methods(const quint32 id, 01252 const QString &securityToken) 01253 { 01254 INIT_ERROR(); 01255 return metaDataDB->methods(id, securityToken); 01256 } 01257 01258 bool CredentialsDB::checkPassword(const quint32 id, 01259 const QString &username, 01260 const QString &password) 01261 { 01262 INIT_ERROR(); 01263 RETURN_IF_NO_SECRETS_DB(false); 01264 SignonIdentityInfo info = metaDataDB->identity(id); 01265 if (info.isUserNameSecret()) { 01266 return secretsStorage->checkPassword(id, username, password); 01267 } else { 01268 return username == info.userName() && 01269 secretsStorage->checkPassword(id, QString(), password); 01270 } 01271 } 01272 01273 SignonIdentityInfo CredentialsDB::credentials(const quint32 id, 01274 bool queryPassword) 01275 { 01276 TRACE() << "id:" << id << "queryPassword:" << queryPassword; 01277 INIT_ERROR(); 01278 SignonIdentityInfo info = metaDataDB->identity(id); 01279 if (queryPassword && !info.isNew() && isSecretsDBOpen()) { 01280 QString username, password; 01281 secretsStorage->loadCredentials(id, username, password); 01282 if (info.isUserNameSecret()) 01283 info.setUserName(username); 01284 info.setPassword(password); 01285 } 01286 return info; 01287 } 01288 01289 QList<SignonIdentityInfo> 01290 CredentialsDB::credentials(const QMap<QString, QString> &filter) 01291 { 01292 INIT_ERROR(); 01293 return metaDataDB->identities(filter); 01294 } 01295 01296 quint32 CredentialsDB::insertCredentials(const SignonIdentityInfo &info, 01297 bool storeSecret) 01298 { 01299 SignonIdentityInfo newInfo = info; 01300 if (!info.isNew()) 01301 newInfo.setNew(); 01302 return updateCredentials(newInfo, storeSecret); 01303 } 01304 01305 quint32 CredentialsDB::updateCredentials(const SignonIdentityInfo &info, 01306 bool storeSecret) 01307 { 01308 INIT_ERROR(); 01309 quint32 id = metaDataDB->updateIdentity(info); 01310 if (id == 0) return id; 01311 01312 if (storeSecret && isSecretsDBOpen()) { 01313 QString password; 01314 if (info.storePassword()) 01315 password = info.password(); 01316 01317 QString userName; 01318 if (info.isUserNameSecret()) 01319 userName = info.userName(); 01320 01321 secretsStorage->updateCredentials(id, userName, password); 01322 } 01323 01324 return id; 01325 } 01326 01327 bool CredentialsDB::removeCredentials(const quint32 id) 01328 { 01329 INIT_ERROR(); 01330 01331 /* We don't allow removing the credentials if the secrets DB is not 01332 * available */ 01333 RETURN_IF_NO_SECRETS_DB(false); 01334 01335 return secretsStorage->removeCredentials(id) && 01336 metaDataDB->removeIdentity(id); 01337 } 01338 01339 bool CredentialsDB::clear() 01340 { 01341 TRACE(); 01342 01343 INIT_ERROR(); 01344 01345 /* We don't allow clearing the DB if the secrets DB is not available */ 01346 RETURN_IF_NO_SECRETS_DB(false); 01347 01348 return secretsStorage->clear() && metaDataDB->clear(); 01349 } 01350 01351 QVariantMap CredentialsDB::loadData(const quint32 id, const QString &method) 01352 { 01353 TRACE() << "Loading:" << id << "," << method; 01354 01355 INIT_ERROR(); 01356 RETURN_IF_NO_SECRETS_DB(QVariantMap()); 01357 if (id == 0) return QVariantMap(); 01358 01359 quint32 methodId = metaDataDB->methodId(method); 01360 if (methodId == 0) return QVariantMap(); 01361 01362 return secretsStorage->loadData(id, methodId); 01363 } 01364 01365 bool CredentialsDB::storeData(const quint32 id, const QString &method, 01366 const QVariantMap &data) 01367 { 01368 TRACE() << "Storing:" << id << "," << method; 01369 01370 INIT_ERROR(); 01371 RETURN_IF_NO_SECRETS_DB(false); 01372 if (id == 0) return false; 01373 01374 quint32 methodId = metaDataDB->methodId(method); 01375 if (methodId == 0) { 01376 bool ok = false; 01377 methodId = metaDataDB->insertMethod(method, &ok); 01378 if (!ok) 01379 return false; 01380 } 01381 01382 return secretsStorage->storeData(id, methodId, data); 01383 } 01384 01385 bool CredentialsDB::removeData(const quint32 id, const QString &method) 01386 { 01387 TRACE() << "Removing:" << id << "," << method; 01388 01389 INIT_ERROR(); 01390 RETURN_IF_NO_SECRETS_DB(false); 01391 if (id == 0) return false; 01392 01393 quint32 methodId; 01394 if (!method.isEmpty()) { 01395 methodId = metaDataDB->methodId(method); 01396 if (methodId == 0) return false; 01397 } else { 01398 methodId = 0; 01399 } 01400 01401 return secretsStorage->removeData(id, methodId); 01402 } 01403 01404 QStringList CredentialsDB::accessControlList(const quint32 identityId) 01405 { 01406 INIT_ERROR(); 01407 return metaDataDB->accessControlList(identityId); 01408 } 01409 01410 QStringList CredentialsDB::ownerList(const quint32 identityId) 01411 { 01412 INIT_ERROR(); 01413 return metaDataDB->ownerList(identityId); 01414 } 01415 01416 QString CredentialsDB::credentialsOwnerSecurityToken(const quint32 identityId) 01417 { 01418 //return first owner token 01419 QStringList owners = ownerList(identityId); 01420 return owners.count() ? owners.at(0) : QString(); 01421 } 01422 01423 bool CredentialsDB::addReference(const quint32 id, 01424 const QString &token, 01425 const QString &reference) 01426 { 01427 INIT_ERROR(); 01428 return metaDataDB->addReference(id, token, reference); 01429 } 01430 01431 bool CredentialsDB::removeReference(const quint32 id, 01432 const QString &token, 01433 const QString &reference) 01434 { 01435 INIT_ERROR(); 01436 return metaDataDB->removeReference(id, token, reference); 01437 } 01438 01439 QStringList CredentialsDB::references(const quint32 id, const QString &token) 01440 { 01441 INIT_ERROR(); 01442 return metaDataDB->references(id, token); 01443 } 01444 01445 } //namespace SignonDaemonNS