signon 8.54

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

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