signon  8.40
credentialsdb.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) 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