signon  8.41
credentialsdb.cpp
Go to the documentation of this file.
1 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of signon
4  *
5  * Copyright (C) 2009-2010 Nokia Corporation.
6  *
7  * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com>
8  * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * version 2.1 as published by the Free Software Foundation.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22  * 02110-1301 USA
23  */
24 
25 #include "credentialsdb.h"
26 #include "signond-common.h"
27 
28 #define INIT_ERROR() ErrorMonitor errorMonitor(this)
29 #define RETURN_IF_NO_SECRETS_DB(retval) \
30  if (!isSecretsDBOpen()) { \
31  TRACE() << "Secrets DB is not available"; \
32  _lastError = noSecretsDB; return retval; \
33  }
34 
35 #define S(s) QLatin1String(s)
36 
37 namespace SignonDaemonNS {
38 
39 static const QString driver = QLatin1String("QSQLITE");
40 
41 SqlDatabase::SqlDatabase(const QString &databaseName,
42  const QString &connectionName,
43  int version):
44  m_lastError(SignOn::CredentialsDBError()),
45  m_version(version),
46  m_database(QSqlDatabase::addDatabase(driver, connectionName))
47 
48 {
49  TRACE() << "Supported Drivers:" << this->supportedDrivers();
50  TRACE() << "DATABASE NAME [" << databaseName << "]";
51 
52  m_database.setDatabaseName(databaseName);
53 }
54 
56 {
57  m_database.commit();
58  m_database.close();
59 }
60 
62 {
63  if (!connect())
64  return false;
65 
66  TRACE() << "Database connection succeeded.";
67 
68  if (!hasTables()) {
69  TRACE() << "Creating SQL table structure...";
70  if (!createTables())
71  return false;
72 
74  BLAME() << "Failed to set database version to: " << m_version
75  << ".This could lead to data loss.";
76  } else {
77  TRACE() << "SQL table structure already created...";
78  // check the DB version
79  QSqlQuery q = exec(S("PRAGMA user_version"));
80  int oldVersion = q.first() ? q.value(0).toInt() : 0;
81  if (oldVersion < m_version)
82  updateDB(oldVersion);
83  }
84 
85  return true;
86 }
87 
88 bool SqlDatabase::updateDB(int version)
89 {
90  TRACE() << "Update DB from version " << version << " to " << m_version;
91  exec(QString::fromLatin1("PRAGMA user_version = %1").arg(m_version));
92  return true;
93 }
94 
96 {
97  if (!m_database.open()) {
98  TRACE() << "Could not open database connection.\n";
99  setLastError(m_database.lastError());
100  return false;
101  }
102  return true;
103 }
104 
106 {
107  m_database.close();
108 }
109 
111 {
112  return m_database.transaction();
113 }
114 
116 {
117  return m_database.commit();
118 }
119 
121 {
122  if (!m_database.rollback())
123  TRACE() << "Rollback failed, db data integrity could be compromised.";
124 }
125 
126 QSqlQuery SqlDatabase::exec(const QString &queryStr)
127 {
128  QSqlQuery query(QString(), m_database);
129 
130  if (!query.prepare(queryStr))
131  TRACE() << "Query prepare warning: " << query.lastQuery();
132 
133  if (!query.exec()) {
134  TRACE() << "Query exec error: " << query.lastQuery();
135  setLastError(query.lastError());
136  TRACE() << errorInfo(query.lastError());
137  } else
138  m_lastError.clear();
139 
140  return query;
141 }
142 
143 QSqlQuery SqlDatabase::exec(QSqlQuery &query)
144 {
145 
146  if (!query.exec()) {
147  TRACE() << "Query exec error: " << query.lastQuery();
148  setLastError(query.lastError());
149  TRACE() << errorInfo(query.lastError());
150  } else
151  m_lastError.clear();
152 
153  return query;
154 }
155 
156 
157 bool SqlDatabase::transactionalExec(const QStringList &queryList)
158 {
159  if (!startTransaction()) {
160  setLastError(m_database.lastError());
161  TRACE() << "Could not start transaction";
162  return false;
163  }
164 
165  bool allOk = true;
166  foreach (QString queryStr, queryList) {
167  TRACE() << QString::fromLatin1("TRANSACT Query [%1]").arg(queryStr);
168  QSqlQuery query = exec(queryStr);
169 
170  if (errorOccurred()) {
171  allOk = false;
172  break;
173  }
174  }
175 
176  if (allOk && commit()) {
177  TRACE() << "Commit SUCCEEDED.";
178  return true;
179  } else {
180  rollback();
181  }
182 
183  TRACE() << "Transactional exec FAILED!";
184  return false;
185 }
186 
187 SignOn::CredentialsDBError SqlDatabase::lastError() const
188 {
189  return m_lastError;
190 }
191 
192 void SqlDatabase::setLastError(const QSqlError &sqlError)
193 {
194  if (sqlError.isValid()) {
195  if (sqlError.type() == QSqlError::ConnectionError) {
196  m_lastError.setType(SignOn::CredentialsDBError::ConnectionError);
197  } else {
198  m_lastError.setType(SignOn::CredentialsDBError::StatementError);
199  }
200  m_lastError.setText(sqlError.text());
201  } else {
202  m_lastError.clear();
203  }
204 }
205 
206 QString SqlDatabase::errorInfo(const QSqlError &error)
207 {
208  if (!error.isValid())
209  return QLatin1String("SQL Error invalid.");
210 
211  QString text;
212  QTextStream stream(&text);
213  stream << "SQL error description:";
214  stream << "\n\tType: ";
215 
216  const char *errType;
217  switch (error.type()) {
218  case QSqlError::NoError: errType = "NoError"; break;
219  case QSqlError::ConnectionError: errType = "ConnectionError"; break;
220  case QSqlError::StatementError: errType = "StatementError"; break;
221  case QSqlError::TransactionError: errType = "TransactionError"; break;
223  /* fall trough */
224  default: errType = "UnknownError";
225  }
226  stream << errType;
227  stream << "\n\tDatabase text: " << error.databaseText();
228  stream << "\n\tDriver text: " << error.driverText();
229  stream << "\n\tNumber: " << error.number();
230 
231  return text;
232 }
233 
234 QStringList SqlDatabase::queryList(const QString &query_str)
235 {
236  QSqlQuery query(QString(), m_database);
237  if (!query.prepare(query_str))
238  TRACE() << "Query prepare warning: " << query.lastQuery();
239  return queryList(query);
240 }
241 
242 QStringList SqlDatabase::queryList(QSqlQuery &q)
243 {
244  QStringList list;
245  QSqlQuery query = exec(q);
246  if (errorOccurred()) return list;
247  while (query.next()) {
248  list.append(query.value(0).toString());
249  }
250  query.clear();
251  return list;
252 }
253 
254 QStringList MetaDataDB::tableUpdates2()
255 {
256  QStringList tableUpdates = QStringList()
257  << QString::fromLatin1(
258  "CREATE TABLE OWNER"
259  "(rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
260  "identity_id INTEGER CONSTRAINT fk_identity_id REFERENCES CREDENTIALS(id) ON DELETE CASCADE,"
261  "token_id INTEGER CONSTRAINT fk_token_id REFERENCES TOKENS(id) ON DELETE CASCADE)")
262  //added triggers for OWNER
263  << QString::fromLatin1(
264  // Foreign Key Preventing insert
265  "CREATE TRIGGER fki_OWNER_token_id_TOKENS_id "
266  "BEFORE INSERT ON [OWNER] "
267  "FOR EACH ROW BEGIN "
268  " SELECT RAISE(ROLLBACK, 'insert on table OWNER violates foreign key constraint fki_OWNER_token_id_TOKENS_id') "
269  " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; "
270  "END; "
271  )
272  << QString::fromLatin1(
273  // Foreign key preventing update
274  "CREATE TRIGGER fku_OWNER_token_id_TOKENS_id "
275  "BEFORE UPDATE ON [OWNER] "
276  "FOR EACH ROW BEGIN "
277  " SELECT RAISE(ROLLBACK, 'update on table OWNER violates foreign key constraint fku_OWNER_token_id_TOKENS_id') "
278  " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; "
279  "END; "
280  )
281  << QString::fromLatin1(
282  // Cascading Delete
283  "CREATE TRIGGER fkdc_OWNER_token_id_TOKENS_id "
284  "BEFORE DELETE ON TOKENS "
285  "FOR EACH ROW BEGIN "
286  " DELETE FROM OWNER WHERE OWNER.token_id = OLD.id; "
287  "END; "
288  );
289 
290  return tableUpdates;
291 }
292 
294 {
295  /* !!! Foreign keys support seems to be disabled, for the moment... */
296  QStringList createTableQuery = QStringList()
297  << QString::fromLatin1(
298  "CREATE TABLE CREDENTIALS"
299  "(id INTEGER PRIMARY KEY AUTOINCREMENT,"
300  "caption TEXT,"
301  "username TEXT,"
302  "flags INTEGER,"
303  "type INTEGER)")
304  << QString::fromLatin1(
305  "CREATE TABLE METHODS"
306  "(id INTEGER PRIMARY KEY AUTOINCREMENT,"
307  "method TEXT UNIQUE)")
308  << QString::fromLatin1(
309  "CREATE TABLE MECHANISMS"
310  "(id INTEGER PRIMARY KEY AUTOINCREMENT,"
311  "mechanism TEXT UNIQUE)")
312  << QString::fromLatin1(
313  "CREATE TABLE TOKENS"
314  "(id INTEGER PRIMARY KEY AUTOINCREMENT,"
315  "token TEXT UNIQUE)")
316  << QString::fromLatin1(
317  "CREATE TABLE REALMS"
318  "(identity_id INTEGER CONSTRAINT fk_identity_id REFERENCES CREDENTIALS(id) ON DELETE CASCADE,"
319  "realm TEXT,"
320  "hostname TEXT,"
321  "PRIMARY KEY (identity_id, realm, hostname))")
322  << QString::fromLatin1(
323  "CREATE TABLE ACL"
324  "(rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
325  "identity_id INTEGER CONSTRAINT fk_identity_id REFERENCES CREDENTIALS(id) ON DELETE CASCADE,"
326  "method_id INTEGER CONSTRAINT fk_method_id REFERENCES METHODS(id) ON DELETE CASCADE,"
327  "mechanism_id INTEGER CONSTRAINT fk_mechanism_id REFERENCES MECHANISMS(id) ON DELETE CASCADE,"
328  "token_id INTEGER CONSTRAINT fk_token_id REFERENCES TOKENS(id) ON DELETE CASCADE)")
329  << QString::fromLatin1(
330  "CREATE TABLE REFS"
331  "(identity_id INTEGER CONSTRAINT fk_identity_id REFERENCES CREDENTIALS(id) ON DELETE CASCADE,"
332  "token_id INTEGER CONSTRAINT fk_token_id REFERENCES TOKENS(id) ON DELETE CASCADE,"
333  "ref TEXT,"
334  "PRIMARY KEY (identity_id, token_id, ref))")
335 
336 /*
337 * triggers generated with
338 * http://www.rcs-comp.com/site/index.php/view/Utilities-SQLite_foreign_key_trigger_generator
339 */
340  //insert triggers to force foreign keys support
341  << QString::fromLatin1(
342  // Foreign Key Preventing insert
343  "CREATE TRIGGER fki_REALMS_identity_id_CREDENTIALS_id "
344  "BEFORE INSERT ON [REALMS] "
345  "FOR EACH ROW BEGIN "
346  " SELECT RAISE(ROLLBACK, 'insert on table REALMS violates foreign key constraint fki_REALMS_identity_id_CREDENTIALS_id') "
347  " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; "
348  "END; "
349  )
350  << QString::fromLatin1(
351  // Foreign key preventing update
352  "CREATE TRIGGER fku_REALMS_identity_id_CREDENTIALS_id "
353  "BEFORE UPDATE ON [REALMS] "
354  "FOR EACH ROW BEGIN "
355  " SELECT RAISE(ROLLBACK, 'update on table REALMS violates foreign key constraint fku_REALMS_identity_id_CREDENTIALS_id') "
356  " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; "
357  "END; "
358  )
359  << QString::fromLatin1(
360  // Cascading Delete
361  "CREATE TRIGGER fkdc_REALMS_identity_id_CREDENTIALS_id "
362  "BEFORE DELETE ON CREDENTIALS "
363  "FOR EACH ROW BEGIN "
364  " DELETE FROM REALMS WHERE REALMS.identity_id = OLD.id; "
365  "END; "
366  )
367  << QString::fromLatin1(
368  // Foreign Key Preventing insert
369  "CREATE TRIGGER fki_ACL_identity_id_CREDENTIALS_id "
370  "BEFORE INSERT ON [ACL] "
371  "FOR EACH ROW BEGIN "
372  " SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign key constraint fki_ACL_identity_id_CREDENTIALS_id') "
373  " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; "
374  "END;"
375  )
376  << QString::fromLatin1(
377  // Foreign key preventing update
378  "CREATE TRIGGER fku_ACL_identity_id_CREDENTIALS_id "
379  "BEFORE UPDATE ON [ACL] "
380  "FOR EACH ROW BEGIN "
381  " SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign key constraint fku_ACL_identity_id_CREDENTIALS_id') "
382  " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; "
383  "END; "
384  )
385  << QString::fromLatin1(
386  // Cascading Delete
387  "CREATE TRIGGER fkdc_ACL_identity_id_CREDENTIALS_id "
388  "BEFORE DELETE ON CREDENTIALS "
389  "FOR EACH ROW BEGIN "
390  " DELETE FROM ACL WHERE ACL.identity_id = OLD.id; "
391  "END; "
392  )
393  << QString::fromLatin1(
394  // Foreign Key Preventing insert
395  "CREATE TRIGGER fki_ACL_method_id_METHODS_id "
396  "BEFORE INSERT ON [ACL] "
397  "FOR EACH ROW BEGIN "
398  " SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign key constraint fki_ACL_method_id_METHODS_id') "
399  " WHERE NEW.method_id IS NOT NULL AND (SELECT id FROM METHODS WHERE id = NEW.method_id) IS NULL; "
400  "END; "
401  )
402  << QString::fromLatin1(
403  // Foreign key preventing update
404  "CREATE TRIGGER fku_ACL_method_id_METHODS_id "
405  "BEFORE UPDATE ON [ACL] "
406  "FOR EACH ROW BEGIN "
407  " SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign key constraint fku_ACL_method_id_METHODS_id') "
408  " WHERE NEW.method_id IS NOT NULL AND (SELECT id FROM METHODS WHERE id = NEW.method_id) IS NULL; "
409  "END; "
410  )
411  << QString::fromLatin1(
412  // Cascading Delete
413  "CREATE TRIGGER fkdc_ACL_method_id_METHODS_id "
414  "BEFORE DELETE ON METHODS "
415  "FOR EACH ROW BEGIN "
416  " DELETE FROM ACL WHERE ACL.method_id = OLD.id; "
417  "END; "
418  )
419  << QString::fromLatin1(
420  // Foreign Key Preventing insert
421  "CREATE TRIGGER fki_ACL_mechanism_id_MECHANISMS_id "
422  "BEFORE INSERT ON [ACL] "
423  "FOR EACH ROW BEGIN "
424  " SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign key constraint fki_ACL_mechanism_id_MECHANISMS_id') "
425  " WHERE NEW.mechanism_id IS NOT NULL AND (SELECT id FROM MECHANISMS WHERE id = NEW.mechanism_id) IS NULL; "
426  "END; "
427  )
428  << QString::fromLatin1(
429  // Foreign key preventing update
430  "CREATE TRIGGER fku_ACL_mechanism_id_MECHANISMS_id "
431  "BEFORE UPDATE ON [ACL] "
432  "FOR EACH ROW BEGIN "
433  " SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign key constraint fku_ACL_mechanism_id_MECHANISMS_id') "
434  " WHERE NEW.mechanism_id IS NOT NULL AND (SELECT id FROM MECHANISMS WHERE id = NEW.mechanism_id) IS NULL; "
435  "END; "
436  )
437  << QString::fromLatin1(
438  // Cascading Delete
439  "CREATE TRIGGER fkdc_ACL_mechanism_id_MECHANISMS_id "
440  "BEFORE DELETE ON MECHANISMS "
441  "FOR EACH ROW BEGIN "
442  " DELETE FROM ACL WHERE ACL.mechanism_id = OLD.id; "
443  "END; "
444  )
445  << QString::fromLatin1(
446  // Foreign Key Preventing insert
447  "CREATE TRIGGER fki_ACL_token_id_TOKENS_id "
448  "BEFORE INSERT ON [ACL] "
449  "FOR EACH ROW BEGIN "
450  " SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign key constraint fki_ACL_token_id_TOKENS_id') "
451  " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; "
452  "END; "
453  )
454  << QString::fromLatin1(
455  // Foreign key preventing update
456  "CREATE TRIGGER fku_ACL_token_id_TOKENS_id "
457  "BEFORE UPDATE ON [ACL] "
458  "FOR EACH ROW BEGIN "
459  " SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign key constraint fku_ACL_token_id_TOKENS_id') "
460  " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; "
461  "END; "
462  )
463  << QString::fromLatin1(
464  // Cascading Delete
465  "CREATE TRIGGER fkdc_ACL_token_id_TOKENS_id "
466  "BEFORE DELETE ON TOKENS "
467  "FOR EACH ROW BEGIN "
468  " DELETE FROM ACL WHERE ACL.token_id = OLD.id; "
469  "END; "
470  )
471  << QString::fromLatin1(
472  // Foreign Key Preventing insert
473  "CREATE TRIGGER fki_REFS_identity_id_CREDENTIALS_id "
474  "BEFORE INSERT ON [REFS] "
475  "FOR EACH ROW BEGIN "
476  " SELECT RAISE(ROLLBACK, 'insert on table REFS violates foreign key constraint fki_REFS_identity_id_CREDENTIALS_id') "
477  " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; "
478  "END; "
479  )
480  << QString::fromLatin1(
481  // Foreign key preventing update
482  "CREATE TRIGGER fku_REFS_identity_id_CREDENTIALS_id "
483  "BEFORE UPDATE ON [REFS] "
484  "FOR EACH ROW BEGIN "
485  " SELECT RAISE(ROLLBACK, 'update on table REFS violates foreign key constraint fku_REFS_identity_id_CREDENTIALS_id') "
486  " WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM CREDENTIALS WHERE id = NEW.identity_id) IS NULL; "
487  "END; "
488  )
489  << QString::fromLatin1(
490  // Cascading Delete
491  "CREATE TRIGGER fkdc_REFS_identity_id_CREDENTIALS_id "
492  "BEFORE DELETE ON CREDENTIALS "
493  "FOR EACH ROW BEGIN "
494  " DELETE FROM REFS WHERE REFS.identity_id = OLD.id; "
495  "END; "
496  )
497  << QString::fromLatin1(
498  // Foreign Key Preventing insert
499  "CREATE TRIGGER fki_REFS_token_id_TOKENS_id "
500  "BEFORE INSERT ON [REFS] "
501  "FOR EACH ROW BEGIN "
502  " SELECT RAISE(ROLLBACK, 'insert on table REFS violates foreign key constraint fki_REFS_token_id_TOKENS_id') "
503  " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; "
504  "END; "
505  )
506  << QString::fromLatin1(
507  // Foreign key preventing update
508  "CREATE TRIGGER fku_REFS_token_id_TOKENS_id "
509  "BEFORE UPDATE ON [REFS] "
510  "FOR EACH ROW BEGIN "
511  " SELECT RAISE(ROLLBACK, 'update on table REFS violates foreign key constraint fku_REFS_token_id_TOKENS_id') "
512  " WHERE NEW.token_id IS NOT NULL AND (SELECT id FROM TOKENS WHERE id = NEW.token_id) IS NULL; "
513  "END; "
514  )
515  << QString::fromLatin1(
516  // Cascading Delete
517  "CREATE TRIGGER fkdc_REFS_token_id_TOKENS_id "
518  "BEFORE DELETE ON TOKENS "
519  "FOR EACH ROW BEGIN "
520  " DELETE FROM REFS WHERE REFS.token_id = OLD.id; "
521  "END; "
522  );
523 /*
524 end of generated code
525 */
526  //insert table updates
527  createTableQuery << tableUpdates2();
528 
529  foreach (QString createTable, createTableQuery) {
530  QSqlQuery query = exec(createTable);
531  if (lastError().isValid()) {
532  TRACE() << "Error occurred while creating the database.";
533  return false;
534  }
535  query.clear();
536  commit();
537  }
538  TRACE() << "Creation successful";
539 
540  return true;
541 }
542 
543 bool MetaDataDB::updateDB(int version)
544 {
545  if (version == m_version)
546  return true;
547 
548  if (version < 1) {
549  TRACE() << "Upgrading from version < 1 not supported. Clearing DB";
550  QString fileName = m_database.databaseName();
551  QString connectionName = m_database.connectionName();
552  m_database.close();
553  QFile::remove(fileName);
554  m_database = QSqlDatabase(QSqlDatabase::addDatabase(driver,
555  connectionName));
556  m_database.setDatabaseName(fileName);
557  if (!connect())
558  return false;
559 
560  if (!createTables())
561  return false;
562  }
563 
564  //convert from 1 to 2
565  if (version == 1) {
566  QStringList createTableQuery = tableUpdates2();
567  foreach (QString createTable, createTableQuery) {
568  QSqlQuery query = exec(createTable);
569  if (lastError().isValid()) {
570  TRACE() << "Error occurred while inseting new tables.";
571  return false;
572  }
573  query.clear();
574  commit();
575  }
576  TRACE() << "Table insert successful";
577 
578  //populate owner table from acl
579  QSqlQuery ownerInsert = exec(S("INSERT OR IGNORE INTO OWNER "
580  "(identity_id, token_id) "
581  " SELECT identity_id, token_id FROM ACL"));
582  if (!commit()){
583  BLAME() << "Table copy failed.";
584  rollback();
585  }
586 
587  } else {
588  return false;
589  }
590 
591  return SqlDatabase::updateDB(version);
592 }
593 
594 QStringList MetaDataDB::methods(const quint32 id, const QString &securityToken)
595 {
596  QStringList list;
597  if (securityToken.isEmpty()) {
598  list = queryList(
599  QString::fromLatin1("SELECT DISTINCT METHODS.method FROM "
600  "( ACL JOIN METHODS ON ACL.method_id = METHODS.id ) "
601  "WHERE ACL.identity_id = '%1'").arg(id)
602  );
603  return list;
604  }
605  QSqlQuery q = newQuery();
606  q.prepare(S("SELECT DISTINCT METHODS.method FROM "
607  "( ACL JOIN METHODS ON ACL.method_id = METHODS.id) "
608  "WHERE ACL.identity_id = :id AND ACL.token_id = "
609  "(SELECT id FROM TOKENS where token = :token)"));
610  q.bindValue(S(":id"), id);
611  q.bindValue(S(":token"), securityToken);
612  list = queryList(q);
613 
614  return list;
615 }
616 
617 quint32 MetaDataDB::methodId(const QString &method)
618 {
619  TRACE() << "method:" << method;
620 
621  QSqlQuery q = newQuery();
622  q.prepare(S("SELECT id FROM METHODS WHERE method = :method"));
623  q.bindValue(S(":method"), method);
624  exec(q);
625  if (!q.first()) {
626  TRACE() << "No result or invalid method query.";
627  return 0;
628  }
629 
630  return q.value(0).toUInt();
631 }
632 
634 {
635  QString query_str;
636 
637  query_str = QString::fromLatin1(
638  "SELECT caption, username, flags, type "
639  "FROM credentials WHERE id = %1").arg(id);
640  QSqlQuery query = exec(query_str);
641 
642  if (!query.first()) {
643  TRACE() << "No result or invalid credentials query.";
644  return SignonIdentityInfo();
645  }
646 
647  QString caption = query.value(0).toString();
648  QString username = query.value(1).toString();
649  int flags = query.value(2).toInt();
650  bool savePassword = flags & RememberPassword;
651  bool validated = flags & Validated;
652  bool isUserNameSecret = flags & UserNameIsSecret;
653  if (isUserNameSecret) username = QString();
654  int type = query.value(3).toInt();
655 
656  query.clear();
657  QStringList realms = queryList(
658  QString::fromLatin1("SELECT realm FROM REALMS "
659  "WHERE identity_id = %1").arg(id));
660 
661  QStringList ownerTokens = queryList(
662  QString::fromLatin1("SELECT token FROM TOKENS "
663  "WHERE id IN "
664  "(SELECT token_id FROM OWNER WHERE identity_id = '%1' )")
665  .arg(id));
666 
667  query_str = QString::fromLatin1("SELECT token FROM TOKENS "
668  "WHERE id IN "
669  "(SELECT token_id FROM ACL WHERE identity_id = '%1' )")
670  .arg(id);
671  query = exec(query_str);
672  QStringList securityTokens;
673  while (query.next()) {
674  securityTokens.append(query.value(0).toString());
675  }
676  query.clear();
678  query_str = QString::fromLatin1(
679  "SELECT DISTINCT ACL.method_id, METHODS.method FROM "
680  "( ACL JOIN METHODS ON ACL.method_id = METHODS.id ) "
681  "WHERE ACL.identity_id = '%1'").arg(id);
682  query = exec(query_str);
683  while (query.next()) {
684  QStringList mechanisms = queryList(
685  QString::fromLatin1("SELECT DISTINCT MECHANISMS.mechanism FROM "
686  "( MECHANISMS JOIN ACL "
687  "ON ACL.mechanism_id = MECHANISMS.id ) "
688  "WHERE ACL.method_id = '%1' AND ACL.identity_id = '%2' ")
689  .arg(query.value(0).toInt()).arg(id));
690  methods.insert(query.value(1).toString(), mechanisms);
691  }
692  query.clear();
693 
694  int refCount = 0;
695  //TODO query for refcount
696 
697  SignonIdentityInfo info =
698  SignonIdentityInfo(id, username, QString(), savePassword,
699  caption, methods, realms, securityTokens,
700  ownerTokens,
701  type, refCount, validated);
702  info.setUserNameSecret(isUserNameSecret);
703  return info;
704 }
705 
706 QList<SignonIdentityInfo> MetaDataDB::identities(const QMap<QString,
707  QString> &filter)
708 {
709  TRACE();
710  Q_UNUSED(filter)
711  QList<SignonIdentityInfo> result;
712 
713  QString queryStr(QString::fromLatin1("SELECT id FROM credentials"));
714 
715  // TODO - process filtering step here !!!
716 
717  queryStr += QString::fromLatin1(" ORDER BY id");
718 
719  QSqlQuery query = exec(queryStr);
720  if (errorOccurred()) {
721  TRACE() << "Error occurred while fetching credentials from database.";
722  return result;
723  }
724 
725  while (query.next()) {
726  SignonIdentityInfo info = identity(query.value(0).toUInt());
727  if (errorOccurred())
728  break;
729  result << info;
730  }
731 
732  query.clear();
733  return result;
734 }
735 
737 {
738  if (!startTransaction()) {
739  TRACE() << "Could not start transaction. Error inserting credentials.";
740  return 0;
741  }
742 
743  quint32 id = updateCredentials(info);
744  if (id == 0) {
745  rollback();
746  return 0;
747  }
748 
749  /* Methods inserts */
750  insertMethods(info.methods());
751 
752  if (!updateRealms(id, info.realms(), info.isNew())) {
753  TRACE() << "Error in updating realms";
754  rollback();
755  return 0;
756  }
757 
758  /* Security tokens insert */
759  foreach (QString token, info.accessControlList()) {
760  QSqlQuery tokenInsert = newQuery();
761  tokenInsert.prepare(S("INSERT OR IGNORE INTO TOKENS (token) "
762  "VALUES ( :token )"));
763  tokenInsert.bindValue(S(":token"), token);
764  exec(tokenInsert);
765  }
766 
767  foreach (QString token, info.ownerList()) {
768  if (!token.isEmpty()) {
769  QSqlQuery tokenInsert = newQuery();
770  tokenInsert.prepare(S("INSERT OR IGNORE INTO TOKENS (token) "
771  "VALUES ( :token )"));
772  tokenInsert.bindValue(S(":token"), token);
773  exec(tokenInsert);
774  }
775  }
776 
777  if (!info.isNew()) {
778  //remove acl
779  QString queryStr = QString::fromLatin1(
780  "DELETE FROM ACL WHERE "
781  "identity_id = '%1'")
782  .arg(info.id());
783  QSqlQuery insertQuery = exec(queryStr);
784  insertQuery.clear();
785  //remove owner
786  queryStr = QString::fromLatin1(
787  "DELETE FROM OWNER WHERE "
788  "identity_id = '%1'")
789  .arg(info.id());
790  insertQuery = exec(queryStr);
791  insertQuery.clear();
792  }
793 
794  /* ACL insert, this will do basically identity level ACL */
795  QMapIterator<QString, QStringList> it(info.methods());
796  while (it.hasNext()) {
797  it.next();
798  if (!info.accessControlList().isEmpty()) {
799  foreach (QString token, info.accessControlList()) {
800  foreach (QString mech, it.value()) {
801  QSqlQuery aclInsert = newQuery();
802  aclInsert.prepare(S("INSERT OR REPLACE INTO ACL "
803  "(identity_id, method_id, mechanism_id, token_id) "
804  "VALUES ( :id, "
805  "( SELECT id FROM METHODS WHERE method = :method ),"
806  "( SELECT id FROM MECHANISMS WHERE mechanism= :mech ), "
807  "( SELECT id FROM TOKENS WHERE token = :token ))"));
808  aclInsert.bindValue(S(":id"), id);
809  aclInsert.bindValue(S(":method"), it.key());
810  aclInsert.bindValue(S(":mech"), mech);
811  aclInsert.bindValue(S(":token"), token);
812  exec(aclInsert);
813  }
814  //insert entires for empty mechs list
815  if (it.value().isEmpty()) {
816  QSqlQuery aclInsert = newQuery();
817  aclInsert.prepare(S("INSERT OR REPLACE INTO ACL (identity_id, method_id, token_id) "
818  "VALUES ( :id, "
819  "( SELECT id FROM METHODS WHERE method = :method ),"
820  "( SELECT id FROM TOKENS WHERE token = :token ))"));
821  aclInsert.bindValue(S(":id"), id);
822  aclInsert.bindValue(S(":method"), it.key());
823  aclInsert.bindValue(S(":token"), token);
824  exec(aclInsert);
825  }
826  }
827  } else {
828  foreach (QString mech, it.value()) {
829  QSqlQuery aclInsert = newQuery();
830  aclInsert.prepare(S("INSERT OR REPLACE INTO ACL "
831  "(identity_id, method_id, mechanism_id) "
832  "VALUES ( :id, "
833  "( SELECT id FROM METHODS WHERE method = :method ),"
834  "( SELECT id FROM MECHANISMS WHERE mechanism= :mech )"
835  ")"));
836  aclInsert.bindValue(S(":id"), id);
837  aclInsert.bindValue(S(":method"), it.key());
838  aclInsert.bindValue(S(":mech"), mech);
839  exec(aclInsert);
840  }
841  //insert entires for empty mechs list
842  if (it.value().isEmpty()) {
843  QSqlQuery aclInsert = newQuery();
844  aclInsert.prepare(S("INSERT OR REPLACE INTO ACL (identity_id, method_id) "
845  "VALUES ( :id, "
846  "( SELECT id FROM METHODS WHERE method = :method )"
847  ")"));
848  aclInsert.bindValue(S(":id"), id);
849  aclInsert.bindValue(S(":method"), it.key());
850  exec(aclInsert);
851  }
852  }
853  }
854  //insert acl in case where methods are missing
855  if (info.methods().isEmpty()) {
856  foreach (QString token, info.accessControlList()) {
857  QSqlQuery aclInsert = newQuery();
858  aclInsert.prepare(S("INSERT OR REPLACE INTO ACL "
859  "(identity_id, token_id) "
860  "VALUES ( :id, "
861  "( SELECT id FROM TOKENS WHERE token = :token ))"));
862  aclInsert.bindValue(S(":id"), id);
863  aclInsert.bindValue(S(":token"), token);
864  exec(aclInsert);
865  }
866  }
867 
868  //insert owner list
869  foreach (QString token, info.ownerList()) {
870  if (!token.isEmpty()) {
871  QSqlQuery ownerInsert = newQuery();
872  ownerInsert.prepare(S("INSERT OR REPLACE INTO OWNER "
873  "(identity_id, token_id) "
874  "VALUES ( :id, "
875  "( SELECT id FROM TOKENS WHERE token = :token ))"));
876  ownerInsert.bindValue(S(":id"), id);
877  ownerInsert.bindValue(S(":token"), token);
878  exec(ownerInsert);
879  }
880  }
881 
882  if (commit()) {
883  return id;
884  } else {
885  rollback();
886  TRACE() << "Credentials insertion failed.";
887  return 0;
888  }
889 }
890 
891 bool MetaDataDB::removeIdentity(const quint32 id)
892 {
893  TRACE();
894 
895  QStringList queries = QStringList()
896  << QString::fromLatin1(
897  "DELETE FROM CREDENTIALS WHERE id = %1").arg(id)
898  << QString::fromLatin1(
899  "DELETE FROM ACL WHERE identity_id = %1").arg(id)
900  << QString::fromLatin1(
901  "DELETE FROM REALMS WHERE identity_id = %1").arg(id)
902  << QString::fromLatin1(
903  "DELETE FROM owner WHERE identity_id = %1").arg(id);
904 
905  return transactionalExec(queries);
906 }
907 
909 {
910  TRACE();
911 
912  QStringList clearCommands = QStringList()
913  << QLatin1String("DELETE FROM CREDENTIALS")
914  << QLatin1String("DELETE FROM METHODS")
915  << QLatin1String("DELETE FROM MECHANISMS")
916  << QLatin1String("DELETE FROM ACL")
917  << QLatin1String("DELETE FROM REALMS")
918  << QLatin1String("DELETE FROM TOKENS")
919  << QLatin1String("DELETE FROM OWNER");
920 
921  return transactionalExec(clearCommands);
922 }
923 
924 QStringList MetaDataDB::accessControlList(const quint32 identityId)
925 {
926  return queryList(QString::fromLatin1("SELECT token FROM TOKENS "
927  "WHERE id IN "
928  "(SELECT token_id FROM ACL WHERE identity_id = '%1' )")
929  .arg(identityId));
930 }
931 
932 QStringList MetaDataDB::ownerList(const quint32 identityId)
933 {
934  return queryList(QString::fromLatin1("SELECT token FROM TOKENS "
935  "WHERE id IN "
936  "(SELECT token_id FROM OWNER WHERE identity_id = '%1' )")
937  .arg(identityId));
938 }
939 
940 bool MetaDataDB::addReference(const quint32 id,
941  const QString &token,
942  const QString &reference)
943 {
944  if (!startTransaction()) {
945  TRACE() << "Could not start transaction. Error inserting data.";
946  return false;
947  }
948 
949  TRACE() << "Storing:" << id << ", " << token << ", " << reference;
950  /* Data insert */
951  bool allOk = true;
952 
953  /* Security token insert */
954  QSqlQuery tokenInsert = newQuery();
955  tokenInsert.prepare(S("INSERT OR IGNORE INTO TOKENS (token) "
956  "VALUES ( :token )"));
957  tokenInsert.bindValue(S(":token"), token);
958  exec(tokenInsert);
959  if (errorOccurred()) {
960  allOk = false;
961  }
962 
963  QSqlQuery refsInsert = newQuery();
964  refsInsert.prepare(S("INSERT OR REPLACE INTO REFS "
965  "(identity_id, token_id, ref) "
966  "VALUES ( :id, "
967  "( SELECT id FROM TOKENS WHERE token = :token ),"
968  ":reference"
969  ")"));
970  refsInsert.bindValue(S(":id"), id);
971  refsInsert.bindValue(S(":token"), token);
972  refsInsert.bindValue(S(":reference"), reference);
973  exec(refsInsert);
974  if (errorOccurred()) {
975  allOk = false;
976  }
977 
978  if (allOk && commit()) {
979  TRACE() << "Data insertion ok.";
980  return true;
981  }
982  rollback();
983  TRACE() << "Data insertion failed.";
984  return false;
985 }
986 
987 bool MetaDataDB::removeReference(const quint32 id,
988  const QString &token,
989  const QString &reference)
990 {
991  TRACE() << "Removing:" << id << ", " << token << ", " << reference;
992  //check that there is references
993  QStringList refs = references(id, token);
994  if (refs.isEmpty())
995  return false;
996  if (!reference.isNull() && !refs.contains(reference))
997  return false;
998 
999  if (!startTransaction()) {
1000  TRACE() << "Could not start transaction. Error removing data.";
1001  return false;
1002  }
1003 
1004  bool allOk = true;
1005  QSqlQuery refsDelete = newQuery();
1006 
1007  if (reference.isEmpty()) {
1008  refsDelete.prepare(S("DELETE FROM REFS "
1009  "WHERE identity_id = :id AND "
1010  "token_id = ( SELECT id FROM TOKENS WHERE token = :token )"));
1011  refsDelete.bindValue(S(":id"), id);
1012  refsDelete.bindValue(S(":token"), token);
1013  } else {
1014  refsDelete.prepare(S("DELETE FROM REFS "
1015  "WHERE identity_id = :id AND "
1016  "token_id = ( SELECT id FROM TOKENS WHERE token = :token ) "
1017  "AND ref = :ref"));
1018  refsDelete.bindValue(S(":id"), id);
1019  refsDelete.bindValue(S(":token"), token);
1020  refsDelete.bindValue(S(":ref"), reference);
1021  }
1022 
1023  exec(refsDelete);
1024  if (errorOccurred()) {
1025  allOk = false;
1026  }
1027 
1028  if (allOk && commit()) {
1029  TRACE() << "Data delete ok.";
1030  return true;
1031  }
1032  rollback();
1033  TRACE() << "Data delete failed.";
1034  return false;
1035 }
1036 
1037 QStringList MetaDataDB::references(const quint32 id, const QString &token)
1038 {
1039  if (token.isEmpty())
1040  return queryList(QString::fromLatin1("SELECT ref FROM REFS "
1041  "WHERE identity_id = '%1'")
1042  .arg(id));
1043  QSqlQuery q = newQuery();
1044  q.prepare(S("SELECT ref FROM REFS "
1045  "WHERE identity_id = :id AND "
1046  "token_id = (SELECT id FROM TOKENS WHERE token = :token )"));
1047  q.bindValue(S(":id"), id);
1048  q.bindValue(S(":token"), token);
1049  return queryList(q);
1050 }
1051 
1052 bool MetaDataDB::insertMethods(QMap<QString, QStringList> methods)
1053 {
1054  bool allOk = true;
1055 
1056  if (methods.isEmpty()) return false;
1057  //insert (unique) method names
1058  QMapIterator<QString, QStringList> it(methods);
1059  while (it.hasNext()) {
1060  it.next();
1061  QSqlQuery methodInsert = newQuery();
1062  methodInsert.prepare(S("INSERT OR IGNORE INTO METHODS (method) "
1063  "VALUES( :method )"));
1064  methodInsert.bindValue(S(":method"), it.key());
1065  exec(methodInsert);
1066  if (errorOccurred()) allOk = false;
1067  //insert (unique) mechanism names
1068  foreach (QString mech, it.value()) {
1069  QSqlQuery mechInsert = newQuery();
1070  mechInsert.prepare(S("INSERT OR IGNORE INTO MECHANISMS (mechanism) "
1071  "VALUES( :mech )"));
1072  mechInsert.bindValue(S(":mech"), mech);
1073  exec(mechInsert);
1074  if (errorOccurred()) allOk = false;
1075  }
1076  }
1077  return allOk;
1078 }
1079 
1080 quint32 MetaDataDB::insertMethod(const QString &method, bool *ok)
1081 {
1082  QSqlQuery q = newQuery();
1083  q.prepare(S("INSERT INTO METHODS (method) VALUES(:method)"));
1084  q.bindValue(S(":method"), method);
1085  exec(q);
1086 
1087  if (errorOccurred()) {
1088  if (ok != 0) *ok = false;
1089  return 0;
1090  }
1091  return q.lastInsertId().toUInt(ok);
1092 }
1093 
1094 quint32 MetaDataDB::updateCredentials(const SignonIdentityInfo &info)
1095 {
1096  quint32 id;
1097  QSqlQuery q = newQuery();
1098 
1099  int flags = 0;
1100  if (info.validated()) flags |= Validated;
1101  if (info.storePassword()) flags |= RememberPassword;
1102  if (info.isUserNameSecret()) flags |= UserNameIsSecret;
1103 
1104  if (!info.isNew()) {
1105  TRACE() << "UPDATE:" << info.id() ;
1106  q.prepare(S("UPDATE CREDENTIALS SET caption = :caption, "
1107  "username = :username, "
1108  "flags = :flags, "
1109  "type = :type WHERE id = :id"));
1110  q.bindValue(S(":id"), info.id());
1111  } else {
1112  TRACE() << "INSERT:" << info.id();
1113  q.prepare(S("INSERT INTO CREDENTIALS "
1114  "(caption, username, flags, type) "
1115  "VALUES(:caption, :username, :flags, :type)"));
1116  }
1117  q.bindValue(S(":username"),
1118  info.isUserNameSecret() ? QString() : info.userName());
1119  q.bindValue(S(":caption"), info.caption());
1120  q.bindValue(S(":flags"), flags);
1121  q.bindValue(S(":type"), info.type());
1122  exec(q);
1123  if (errorOccurred()) {
1124  TRACE() << "Error occurred while updating crendentials";
1125  return 0;
1126  }
1127 
1128  if (info.isNew()) {
1129  /* Fetch id of the inserted credentials */
1130  QVariant idVariant = q.lastInsertId();
1131  if (!idVariant.isValid()) {
1132  TRACE() << "Error occurred while inserting crendentials";
1133  return 0;
1134  }
1135  id = idVariant.toUInt();
1136  } else {
1137  id = info.id() ;
1138  }
1139 
1140  return id;
1141 }
1142 
1143 bool MetaDataDB::updateRealms(quint32 id, const QStringList &realms, bool isNew)
1144 {
1145  QString queryStr;
1146 
1147  if (!isNew) {
1148  //remove realms list
1149  queryStr = QString::fromLatin1(
1150  "DELETE FROM REALMS WHERE identity_id = '%1'")
1151  .arg(id);
1152  exec(queryStr);
1153  }
1154 
1155  /* Realms insert */
1156  QSqlQuery q = newQuery();
1157  q.prepare(S("INSERT OR IGNORE INTO REALMS (identity_id, realm) "
1158  "VALUES (:id, :realm)"));
1159  foreach (QString realm, realms) {
1160  q.bindValue(S(":id"), id);
1161  q.bindValue(S(":realm"), realm);
1162  exec(q);
1163  if (errorOccurred()) return false;
1164  }
1165  return true;
1166 }
1167 
1168 /* Error monitor class */
1169 
1171 {
1172  db->_lastError.setType(SignOn::CredentialsDBError::NoError);
1173  db->metaDataDB->clearError();
1174  if (db->secretsStorage != 0)
1175  db->secretsStorage->clearError();
1176  _db = db;
1177 }
1178 
1179 CredentialsDB::ErrorMonitor::~ErrorMonitor()
1180 {
1181  /* If there's an error set on the CredentialsDB, just let it be and return.
1182  * If not, take the error from the SqlDatabase objects, if any.
1183  */
1184  if (_db->_lastError.isValid())
1185  return;
1186 
1187  if (_db->secretsStorage != 0 &&
1188  _db->secretsStorage->lastError().isValid()) {
1189  _db->_lastError = _db->secretsStorage->lastError();
1190  return;
1191  }
1192 
1193  _db->_lastError = _db->metaDataDB->lastError();
1194 }
1195 
1196 /* ------- CredentialsDB implementation ------- */
1197 
1198 CredentialsDB::CredentialsDB(const QString &metaDataDbName,
1199  SignOn::AbstractSecretsStorage *secretsStorage):
1200  secretsStorage(secretsStorage),
1201  metaDataDB(new MetaDataDB(metaDataDbName))
1202 {
1203  noSecretsDB = SignOn::CredentialsDBError(
1204  QLatin1String("Secrets DB not opened"),
1205  SignOn::CredentialsDBError::ConnectionError);
1206 }
1207 
1209 {
1210  TRACE();
1211  if (metaDataDB) {
1212  QString connectionName = metaDataDB->connectionName();
1213  delete metaDataDB;
1214  QSqlDatabase::removeDatabase(connectionName);
1215  }
1216 }
1217 
1219 {
1220  return metaDataDB->init();
1221 }
1222 
1223 bool CredentialsDB::openSecretsDB(const QString &secretsDbName)
1224 {
1225  QVariantMap configuration;
1226  configuration.insert(QLatin1String("name"), secretsDbName);
1227  if (!secretsStorage->initialize(configuration)) {
1228  TRACE() << "SecretsStorage initialization failed: " <<
1229  secretsStorage->lastError().text();
1230  return false;
1231  }
1232 
1233  return true;
1234 }
1235 
1237 {
1238  return secretsStorage != 0 && secretsStorage->isOpen();
1239 }
1240 
1242 {
1243  if (secretsStorage != 0) secretsStorage->close();
1244 }
1245 
1246 SignOn::CredentialsDBError CredentialsDB::lastError() const
1247 {
1248  return _lastError;
1249 }
1250 
1251 QStringList CredentialsDB::methods(const quint32 id,
1252  const QString &securityToken)
1253 {
1254  INIT_ERROR();
1255  return metaDataDB->methods(id, securityToken);
1256 }
1257 
1258 bool CredentialsDB::checkPassword(const quint32 id,
1259  const QString &username,
1260  const QString &password)
1261 {
1262  INIT_ERROR();
1263  RETURN_IF_NO_SECRETS_DB(false);
1264  SignonIdentityInfo info = metaDataDB->identity(id);
1265  if (info.isUserNameSecret()) {
1266  return secretsStorage->checkPassword(id, username, password);
1267  } else {
1268  return username == info.userName() &&
1269  secretsStorage->checkPassword(id, QString(), password);
1270  }
1271 }
1272 
1274  bool queryPassword)
1275 {
1276  TRACE() << "id:" << id << "queryPassword:" << queryPassword;
1277  INIT_ERROR();
1278  SignonIdentityInfo info = metaDataDB->identity(id);
1279  if (queryPassword && !info.isNew() && isSecretsDBOpen()) {
1280  QString username, password;
1281  secretsStorage->loadCredentials(id, username, password);
1282  if (info.isUserNameSecret())
1283  info.setUserName(username);
1284  info.setPassword(password);
1285  }
1286  return info;
1287 }
1288 
1289 QList<SignonIdentityInfo>
1290 CredentialsDB::credentials(const QMap<QString, QString> &filter)
1291 {
1292  INIT_ERROR();
1293  return metaDataDB->identities(filter);
1294 }
1295 
1297  bool storeSecret)
1298 {
1299  SignonIdentityInfo newInfo = info;
1300  if (!info.isNew())
1301  newInfo.setNew();
1302  return updateCredentials(newInfo, storeSecret);
1303 }
1304 
1306  bool storeSecret)
1307 {
1308  INIT_ERROR();
1309  quint32 id = metaDataDB->updateIdentity(info);
1310  if (id == 0) return id;
1311 
1312  if (storeSecret && isSecretsDBOpen()) {
1313  QString password;
1314  if (info.storePassword())
1315  password = info.password();
1316 
1317  QString userName;
1318  if (info.isUserNameSecret())
1319  userName = info.userName();
1320 
1321  secretsStorage->updateCredentials(id, userName, password);
1322  }
1323 
1324  return id;
1325 }
1326 
1327 bool CredentialsDB::removeCredentials(const quint32 id)
1328 {
1329  INIT_ERROR();
1330 
1331  /* We don't allow removing the credentials if the secrets DB is not
1332  * available */
1333  RETURN_IF_NO_SECRETS_DB(false);
1334 
1335  return secretsStorage->removeCredentials(id) &&
1336  metaDataDB->removeIdentity(id);
1337 }
1338 
1340 {
1341  TRACE();
1342 
1343  INIT_ERROR();
1344 
1345  /* We don't allow clearing the DB if the secrets DB is not available */
1346  RETURN_IF_NO_SECRETS_DB(false);
1347 
1348  return secretsStorage->clear() && metaDataDB->clear();
1349 }
1350 
1351 QVariantMap CredentialsDB::loadData(const quint32 id, const QString &method)
1352 {
1353  TRACE() << "Loading:" << id << "," << method;
1354 
1355  INIT_ERROR();
1356  RETURN_IF_NO_SECRETS_DB(QVariantMap());
1357  if (id == 0) return QVariantMap();
1358 
1359  quint32 methodId = metaDataDB->methodId(method);
1360  if (methodId == 0) return QVariantMap();
1361 
1362  return secretsStorage->loadData(id, methodId);
1363 }
1364 
1365 bool CredentialsDB::storeData(const quint32 id, const QString &method,
1366  const QVariantMap &data)
1367 {
1368  TRACE() << "Storing:" << id << "," << method;
1369 
1370  INIT_ERROR();
1371  RETURN_IF_NO_SECRETS_DB(false);
1372  if (id == 0) return false;
1373 
1374  quint32 methodId = metaDataDB->methodId(method);
1375  if (methodId == 0) {
1376  bool ok = false;
1377  methodId = metaDataDB->insertMethod(method, &ok);
1378  if (!ok)
1379  return false;
1380  }
1381 
1382  return secretsStorage->storeData(id, methodId, data);
1383 }
1384 
1385 bool CredentialsDB::removeData(const quint32 id, const QString &method)
1386 {
1387  TRACE() << "Removing:" << id << "," << method;
1388 
1389  INIT_ERROR();
1390  RETURN_IF_NO_SECRETS_DB(false);
1391  if (id == 0) return false;
1392 
1393  quint32 methodId;
1394  if (!method.isEmpty()) {
1395  methodId = metaDataDB->methodId(method);
1396  if (methodId == 0) return false;
1397  } else {
1398  methodId = 0;
1399  }
1400 
1401  return secretsStorage->removeData(id, methodId);
1402 }
1403 
1404 QStringList CredentialsDB::accessControlList(const quint32 identityId)
1405 {
1406  INIT_ERROR();
1407  return metaDataDB->accessControlList(identityId);
1408 }
1409 
1410 QStringList CredentialsDB::ownerList(const quint32 identityId)
1411 {
1412  INIT_ERROR();
1413  return metaDataDB->ownerList(identityId);
1414 }
1415 
1416 QString CredentialsDB::credentialsOwnerSecurityToken(const quint32 identityId)
1417 {
1418  //return first owner token
1419  QStringList owners = ownerList(identityId);
1420  return owners.count() ? owners.at(0) : QString();
1421 }
1422 
1423 bool CredentialsDB::addReference(const quint32 id,
1424  const QString &token,
1425  const QString &reference)
1426 {
1427  INIT_ERROR();
1428  return metaDataDB->addReference(id, token, reference);
1429 }
1430 
1431 bool CredentialsDB::removeReference(const quint32 id,
1432  const QString &token,
1433  const QString &reference)
1434 {
1435  INIT_ERROR();
1436  return metaDataDB->removeReference(id, token, reference);
1437 }
1438 
1439 QStringList CredentialsDB::references(const quint32 id, const QString &token)
1440 {
1441  INIT_ERROR();
1442  return metaDataDB->references(id, token);
1443 }
1444 
1445 } //namespace SignonDaemonNS