signon  8.42
signonsessioncore.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of signon
3  *
4  * Copyright (C) 2009-2010 Nokia Corporation.
5  * Copyright (C) 2011 Intel Corporation.
6  *
7  * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
8  * Contact: Jussi Laako <jussi.laako@linux.intel.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 "signond-common.h"
26 #include "signonauthsession.h"
27 #include "signonidentityinfo.h"
28 #include "signonidentity.h"
30 #include "signonui_interface.h"
32 
33 #include "SignOn/uisessiondata_priv.h"
34 #include "SignOn/authpluginif.h"
35 #include "SignOn/signonerror.h"
36 
37 #define MAX_IDLE_TIME SIGNOND_MAX_IDLE_TIME
38 /*
39  * the watchdog searches for idle sessions with period of half of idle timeout
40  * */
41 #define IDLE_WATCHDOG_TIMEOUT SIGNOND_MAX_IDLE_TIME * 500
42 
43 #define SSO_KEY_USERNAME QLatin1String("UserName")
44 #define SSO_KEY_PASSWORD QLatin1String("Secret")
45 #define SSO_KEY_CAPTION QLatin1String("Caption")
46 
47 using namespace SignonDaemonNS;
48 
49 /*
50  * cache of session queues, as was mentined they cannot be static
51  * */
52 QMap<QString, SignonSessionCore *> sessionsOfStoredCredentials;
53 /*
54  * List of "zero" authsessions, needed for global signout
55  * */
56 QList<SignonSessionCore *> sessionsOfNonStoredCredentials;
57 
58 static QVariantMap filterVariantMap(const QVariantMap &other)
59 {
60  QVariantMap result;
61 
62  foreach(QString key, other.keys()) {
63  if (!other.value(key).isNull() && other.value(key).isValid())
64  result.insert(key, other.value(key));
65  }
66 
67  return result;
68 }
69 
70 static QString sessionName(const quint32 id, const QString &method)
71 {
72  return QString::number(id) + QLatin1String("+") + method;
73 }
74 
76  const QString &method,
77  int timeout,
78  SignonDaemon *parent):
79  SignonDisposable(timeout, parent),
80  m_id(id),
81  m_method(method),
82  m_queryCredsUiDisplayed(false)
83 {
84  m_signonui = NULL;
85  m_watcher = NULL;
86 
87  m_signonui = new SignonUiAdaptor(SIGNON_UI_SERVICE,
89  QDBusConnection::sessionBus());
90 
91 
93  SIGNAL(credentialsSystemReady()),
94  SLOT(credentialsSystemReady()));
95 }
96 
98 {
99  delete m_plugin;
100  delete m_watcher;
101  delete m_signonui;
102 
103  m_plugin = NULL;
104  m_signonui = NULL;
105  m_watcher = NULL;
106 }
107 
109  const QString &method,
110  SignonDaemon *parent)
111 {
112  QString objectName;
113  QString key = sessionName(id, method);
114 
115  if (id) {
116  if (sessionsOfStoredCredentials.contains(key)) {
117  return sessionsOfStoredCredentials.value(key);
118  }
119  }
120 
121  SignonSessionCore *ssc = new SignonSessionCore(id, method,
122  parent->authSessionTimeout(),
123  parent);
124 
125  if (ssc->setupPlugin() == false) {
126  TRACE() << "The resulted object is corrupted and has to be deleted";
127  delete ssc;
128  return NULL;
129  }
130 
131  if (id)
132  sessionsOfStoredCredentials.insert(key, ssc);
133  else
134  sessionsOfNonStoredCredentials.append(ssc);
135 
136  TRACE() << "The new session is created :" << key;
137  return ssc;
138 }
139 
140 quint32 SignonSessionCore::id() const
141 {
142  TRACE();
143  keepInUse();
144  return m_id;
145 }
146 
148 {
149  TRACE();
150  keepInUse();
151  return m_method;
152 }
153 
155 {
156  m_plugin = PluginProxy::createNewPluginProxy(m_method);
157 
158  if (!m_plugin) {
159  TRACE() << "Plugin of type " << m_method << " cannot be found";
160  return false;
161  }
162 
163  connect(m_plugin,
164  SIGNAL(processResultReply(const QString&, const QVariantMap&)),
165  this,
166  SLOT(processResultReply(const QString&, const QVariantMap&)),
167  Qt::DirectConnection);
168 
169  connect(m_plugin,
170  SIGNAL(processStore(const QString&, const QVariantMap&)),
171  this,
172  SLOT(processStore(const QString&, const QVariantMap&)),
173  Qt::DirectConnection);
174 
175  connect(m_plugin,
176  SIGNAL(processUiRequest(const QString&, const QVariantMap&)),
177  this,
178  SLOT(processUiRequest(const QString&, const QVariantMap&)),
179  Qt::DirectConnection);
180 
181  connect(m_plugin,
182  SIGNAL(processRefreshRequest(const QString&, const QVariantMap&)),
183  this,
184  SLOT(processRefreshRequest(const QString&, const QVariantMap&)),
185  Qt::DirectConnection);
186 
187  connect(m_plugin,
188  SIGNAL(processError(const QString&, int, const QString&)),
189  this,
190  SLOT(processError(const QString&, int, const QString&)),
191  Qt::DirectConnection);
192 
193  connect(m_plugin,
194  SIGNAL(stateChanged(const QString&, int, const QString&)),
195  this,
196  SLOT(stateChangedSlot(const QString&, int, const QString&)),
197  Qt::DirectConnection);
198 
199  return true;
200 }
201 
203 {
204  qDeleteAll(sessionsOfStoredCredentials);
206 
207  qDeleteAll(sessionsOfNonStoredCredentials);
209 }
210 
211 QStringList SignonSessionCore::loadedPluginMethods(const QString &method)
212 {
213  foreach (SignonSessionCore *corePtr, sessionsOfStoredCredentials) {
214  if (corePtr->method() == method)
215  return corePtr->queryAvailableMechanisms(QStringList());
216  }
217 
219  if (corePtr->method() == method)
220  return corePtr->queryAvailableMechanisms(QStringList());
221  }
222 
223  return QStringList();
224 }
225 
226 QStringList
227 SignonSessionCore::queryAvailableMechanisms(const QStringList &wantedMechanisms)
228 {
229  keepInUse();
230 
231  if (!wantedMechanisms.size())
232  return m_plugin->mechanisms();
233 
234  return m_plugin->mechanisms().toSet().
235  intersect(wantedMechanisms.toSet()).toList();
236 }
237 
238 void SignonSessionCore::process(const QDBusConnection &connection,
239  const QDBusMessage &message,
240  const QVariantMap &sessionDataVa,
241  const QString &mechanism,
242  const QString &cancelKey)
243 {
244  keepInUse();
245  m_listOfRequests.enqueue(RequestData(connection,
246  message,
247  sessionDataVa,
248  mechanism,
249  cancelKey));
250 
251  if (CredentialsAccessManager::instance()->isCredentialsSystemReady())
252  QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
253 }
254 
255 void SignonSessionCore::cancel(const QString &cancelKey)
256 {
257  TRACE();
258 
259  int requestIndex;
260  for (requestIndex = 0;
261  requestIndex < m_listOfRequests.size();
262  requestIndex++) {
263  if (m_listOfRequests.at(requestIndex).m_cancelKey == cancelKey)
264  break;
265  }
266 
267  TRACE() << "The request is found with index " << requestIndex;
268 
269  if (requestIndex < m_listOfRequests.size()) {
270  if (requestIndex == 0) {
271  m_canceled = cancelKey;
272  m_plugin->cancel();
273 
274  if (m_watcher && !m_watcher->isFinished()) {
275  m_signonui->cancelUiRequest(cancelKey);
276  delete m_watcher;
277  m_watcher = 0;
278  }
279  }
280 
281  /*
282  * We must let to the m_listOfRequests to have the canceled request data
283  * in order to delay the next request execution until the actual cancelation
284  * will happen. We will know about that precisely: plugin must reply via
285  * resultSlot or via errorSlot.
286  * */
287  RequestData rd((requestIndex == 0 ?
288  m_listOfRequests.head() :
289  m_listOfRequests.takeAt(requestIndex)));
290 
291  QDBusMessage errReply =
292  rd.m_msg.createErrorReply(SIGNOND_SESSION_CANCELED_ERR_NAME,
293  SIGNOND_SESSION_CANCELED_ERR_STR);
294  rd.m_conn.send(errReply);
295  TRACE() << "Size of the queue is " << m_listOfRequests.size();
296  }
297 }
298 
299 void SignonSessionCore::setId(quint32 id)
300 {
301  keepInUse();
302 
303  if (m_id == id)
304  return;
305 
306  QString key;
307 
308  if (id == 0) {
309  key = sessionName(m_id, m_method);
311  sessionsOfStoredCredentials.take(key));
312  } else {
313  key = sessionName(id, m_method);
314  if (sessionsOfStoredCredentials.contains(key)) {
315  qCritical() << "attempt to assign existing id";
316  return;
317  }
318 
319  sessionsOfNonStoredCredentials.removeOne(this);
320  sessionsOfStoredCredentials[key] = this;
321  }
322  m_id = id;
323 }
324 
325 void SignonSessionCore::startProcess()
326 {
327 
328  TRACE() << "the number of requests is : " << m_listOfRequests.length();
329 
330  keepInUse();
331 
332  RequestData data = m_listOfRequests.head();
333  QVariantMap parameters = data.m_params;
334 
335  /* save the client data; this should not be modified during the processing
336  * of this request */
337  m_clientData = parameters;
338 
339  if (m_id) {
340  CredentialsDB *db =
342  Q_ASSERT(db != 0);
343 
344  SignonIdentityInfo info = db->credentials(m_id);
345  if (info.id() != SIGNOND_NEW_IDENTITY) {
346  if (!parameters.contains(SSO_KEY_PASSWORD)) {
347  parameters[SSO_KEY_PASSWORD] = info.password();
348  }
349  //database overrules over sessiondata for validated username,
350  //so that identity cannot be misused
351  if (info.validated() || !parameters.contains(SSO_KEY_USERNAME)) {
352  parameters[SSO_KEY_USERNAME] = info.userName();
353  }
354 
355  QStringList paramsTokenList;
356  QStringList identityAclList = info.accessControlList();
357 
358  foreach(QString acl, identityAclList)
359  if (AccessControlManagerHelper::instance()->isPeerAllowedToAccess(data.m_msg, acl))
360  paramsTokenList.append(acl);
361 
362  if (!paramsTokenList.isEmpty()) {
363  parameters[SSO_ACCESS_CONTROL_TOKENS] = paramsTokenList;
364  }
365  } else {
366  BLAME() << "Error occurred while getting data from credentials "
367  "database.";
368  }
369 
370  QVariantMap storedParams = db->loadData(m_id, m_method);
371 
372  //parameters will overwrite any common keys on stored params
373  parameters = mergeVariantMaps(storedParams, parameters);
374  }
375 
376  if (parameters.contains(SSOUI_KEY_UIPOLICY)
377  && parameters[SSOUI_KEY_UIPOLICY] == RequestPasswordPolicy) {
378  parameters.remove(SSO_KEY_PASSWORD);
379  }
380 
381  /* Temporary caching, if credentials are valid
382  * this data will be effectively cached */
383  m_tmpUsername = parameters[SSO_KEY_USERNAME].toString();
384  m_tmpPassword = parameters[SSO_KEY_PASSWORD].toString();
385 
386  if (!m_plugin->process(data.m_cancelKey, parameters, data.m_mechanism)) {
387  QDBusMessage errReply =
388  data.m_msg.createErrorReply(SIGNOND_RUNTIME_ERR_NAME,
389  SIGNOND_RUNTIME_ERR_STR);
390  data.m_conn.send(errReply);
391  m_listOfRequests.removeFirst();
392  QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
393  } else
394  stateChangedSlot(data.m_cancelKey, SignOn::SessionStarted,
395  QLatin1String("The request is started successfully"));
396 }
397 
398 void SignonSessionCore::replyError(const QDBusConnection &conn,
399  const QDBusMessage &msg,
400  int err, const QString &message)
401 {
402  keepInUse();
403 
404  QString errName;
405  QString errMessage;
406 
407  //TODO this is needed for old error codes
408  if( err < Error::AuthSessionErr) {
409  BLAME() << "Deprecated error code: " << err;
410  if (message.isEmpty())
411  errMessage = SIGNOND_UNKNOWN_ERR_STR;
412  else
413  errMessage = message;
414  errName = SIGNOND_UNKNOWN_ERR_NAME;
415  }
416 
417  if (Error::AuthSessionErr < err && err < Error::UserErr) {
418  switch(err) {
419  case Error::MechanismNotAvailable:
420  errName = SIGNOND_MECHANISM_NOT_AVAILABLE_ERR_NAME;
421  errMessage = SIGNOND_MECHANISM_NOT_AVAILABLE_ERR_STR;
422  break;
423  case Error::MissingData:
424  errName = SIGNOND_MISSING_DATA_ERR_NAME;
425  errMessage = SIGNOND_MISSING_DATA_ERR_STR;
426  break;
427  case Error::InvalidCredentials:
428  errName = SIGNOND_INVALID_CREDENTIALS_ERR_NAME;
429  errMessage = SIGNOND_INVALID_CREDENTIALS_ERR_STR;
430  break;
431  case Error::NotAuthorized:
432  errName = SIGNOND_NOT_AUTHORIZED_ERR_NAME;
433  errMessage = SIGNOND_NOT_AUTHORIZED_ERR_STR;
434  break;
435  case Error::WrongState:
436  errName = SIGNOND_WRONG_STATE_ERR_NAME;
437  errMessage = SIGNOND_WRONG_STATE_ERR_STR;
438  break;
439  case Error::OperationNotSupported:
440  errName = SIGNOND_OPERATION_NOT_SUPPORTED_ERR_NAME;
441  errMessage = SIGNOND_OPERATION_NOT_SUPPORTED_ERR_STR;
442  break;
443  case Error::NoConnection:
444  errName = SIGNOND_NO_CONNECTION_ERR_NAME;
445  errMessage = SIGNOND_NO_CONNECTION_ERR_STR;
446  break;
447  case Error::Network:
448  errName = SIGNOND_NETWORK_ERR_NAME;
449  errMessage = SIGNOND_NETWORK_ERR_STR;
450  break;
451  case Error::Ssl:
452  errName = SIGNOND_SSL_ERR_NAME;
453  errMessage = SIGNOND_SSL_ERR_STR;
454  break;
455  case Error::Runtime:
456  errName = SIGNOND_RUNTIME_ERR_NAME;
457  errMessage = SIGNOND_RUNTIME_ERR_STR;
458  break;
459  case Error::SessionCanceled:
460  errName = SIGNOND_SESSION_CANCELED_ERR_NAME;
461  errMessage = SIGNOND_SESSION_CANCELED_ERR_STR;
462  break;
463  case Error::TimedOut:
464  errName = SIGNOND_TIMED_OUT_ERR_NAME;
465  errMessage = SIGNOND_TIMED_OUT_ERR_STR;
466  break;
467  case Error::UserInteraction:
468  errName = SIGNOND_USER_INTERACTION_ERR_NAME;
469  errMessage = SIGNOND_USER_INTERACTION_ERR_STR;
470  break;
471  case Error::OperationFailed:
472  errName = SIGNOND_OPERATION_FAILED_ERR_NAME;
473  errMessage = SIGNOND_OPERATION_FAILED_ERR_STR;
474  break;
475  case Error::EncryptionFailure:
476  errName = SIGNOND_ENCRYPTION_FAILED_ERR_NAME;
477  errMessage = SIGNOND_ENCRYPTION_FAILED_ERR_STR;
478  break;
479  case Error::TOSNotAccepted:
480  errName = SIGNOND_TOS_NOT_ACCEPTED_ERR_NAME;
481  errMessage = SIGNOND_TOS_NOT_ACCEPTED_ERR_STR;
482  break;
483  case Error::ForgotPassword:
484  errName = SIGNOND_FORGOT_PASSWORD_ERR_NAME;
485  errMessage = SIGNOND_FORGOT_PASSWORD_ERR_STR;
486  break;
487  case Error::IncorrectDate:
488  errName = SIGNOND_INCORRECT_DATE_ERR_NAME;
489  errMessage = SIGNOND_INCORRECT_DATE_ERR_STR;
490  break;
491  default:
492  if (message.isEmpty())
493  errMessage = SIGNOND_UNKNOWN_ERR_STR;
494  else
495  errMessage = message;
496  errName = SIGNOND_UNKNOWN_ERR_NAME;
497  break;
498  };
499  }
500 
501  if (err > Error::UserErr) {
502  errName = SIGNOND_USER_ERROR_ERR_NAME;
503  errMessage = (QString::fromLatin1("%1:%2")).arg(err).arg(message);
504  }
505 
506  QDBusMessage errReply;
507  errReply = msg.createErrorReply(errName,
508  (message.isEmpty() ? errMessage : message));
509  conn.send(errReply);
510 }
511 
512 void SignonSessionCore::processStoreOperation(const StoreOperation &operation)
513 {
514  TRACE() << "Processing store operation.";
516  Q_ASSERT(db != 0);
517 
518  if (operation.m_storeType != StoreOperation::Blob) {
519  if (!(db->updateCredentials(operation.m_info))) {
520  BLAME() << "Error occured while updating credentials.";
521  }
522  } else {
523  TRACE() << "Processing --- StoreOperation::Blob";
524 
525  if(!db->storeData(m_id,
526  operation.m_authMethod,
527  operation.m_blobData)) {
528  BLAME() << "Error occured while storing data.";
529  }
530  }
531 }
532 
533 void SignonSessionCore::processResultReply(const QString &cancelKey,
534  const QVariantMap &data)
535 {
536  TRACE();
537 
538  keepInUse();
539 
540  if (!m_listOfRequests.size())
541  return;
542 
543  RequestData rd = m_listOfRequests.dequeue();
544 
545  if (cancelKey != m_canceled) {
546  QVariantList arguments;
547  QVariantMap filteredData = filterVariantMap(data);
548 
549  CredentialsAccessManager *camManager =
551  CredentialsDB *db = camManager->credentialsDB();
552  Q_ASSERT(db != 0);
553 
554  //update database entry
555  if (m_id != SIGNOND_NEW_IDENTITY) {
556  SignonIdentityInfo info = db->credentials(m_id);
557  bool identityWasValidated = info.validated();
558 
559  /* update username and password from ui interaction; do not allow
560  * updating the username if the identity is validated */
561  if (!info.validated() && !m_tmpUsername.isEmpty()) {
562  info.setUserName(m_tmpUsername);
563  }
564  if (!m_tmpPassword.isEmpty()) {
565  info.setPassword(m_tmpPassword);
566  }
567  info.setValidated(true);
568 
570  storeOp.m_info = info;
571  processStoreOperation(storeOp);
572 
573  /* If the credentials are validated, the secrets db is not
574  * available and not authorized keys are available, then
575  * the store operation has been performed on the memory
576  * cache only; inform the CAM about the situation. */
577  if (identityWasValidated && !db->isSecretsDBOpen()) {
578  /* Send the storage not available event only if the curent
579  * result processing is following a previous signon UI query.
580  * This is to avoid unexpected UI pop-ups. */
581 
582  if (m_queryCredsUiDisplayed) {
583  SecureStorageEvent *event =
584  new SecureStorageEvent(
586 
587  event->m_sender = static_cast<QObject *>(this);
588 
589  QCoreApplication::postEvent(
591  event,
592  Qt::HighEventPriority);
593  }
594  }
595  }
596 
597  m_tmpUsername.clear();
598  m_tmpPassword.clear();
599 
600  //remove secret field from output
601  if (m_method != QLatin1String("password")
602  && filteredData.contains(SSO_KEY_PASSWORD))
603  filteredData.remove(SSO_KEY_PASSWORD);
604 
605  arguments << filteredData;
606  rd.m_conn.send(rd.m_msg.createReply(arguments));
607 
608  m_canceled = QString();
609 
610  if (m_watcher && !m_watcher->isFinished()) {
611  m_signonui->cancelUiRequest(rd.m_cancelKey);
612  delete m_watcher;
613  m_watcher = 0;
614  }
615  m_queryCredsUiDisplayed = false;
616  }
617  m_canceled = QString();
618  QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
619 }
620 
621 void SignonSessionCore::processStore(const QString &cancelKey,
622  const QVariantMap &data)
623 {
624  Q_UNUSED(cancelKey);
625  TRACE();
626 
627  keepInUse();
628  if (m_id == SIGNOND_NEW_IDENTITY) {
629  BLAME() << "Cannot store without identity";
630  return;
631  }
632  QVariantMap filteredData = data;
633  //do not store username or password
634  filteredData.remove(SSO_KEY_PASSWORD);
635  filteredData.remove(SSO_KEY_USERNAME);
636  filteredData.remove(SSO_ACCESS_CONTROL_TOKENS);
637 
638  //store data into db
640  Q_ASSERT(db != NULL);
641 
643  storeOp.m_blobData = filteredData;
644  storeOp.m_authMethod = m_method;
645  processStoreOperation(storeOp);
646 
647  /* If the credentials are validated, the secrets db is not available and
648  * not authorized keys are available inform the CAM about the situation. */
649  SignonIdentityInfo info = db->credentials(m_id);
650  if (info.validated() && !db->isSecretsDBOpen()) {
651  /* Send the storage not available event only if the curent store
652  * processing is following a previous signon UI query. This is to avoid
653  * unexpected UI pop-ups.
654  */
655  if (m_queryCredsUiDisplayed) {
656  TRACE() << "Secure storage not available.";
657 
658  SecureStorageEvent *event =
659  new SecureStorageEvent(
661  event->m_sender = static_cast<QObject *>(this);
662 
663  QCoreApplication::postEvent(
665  event,
666  Qt::HighEventPriority);
667  }
668  }
669 
670  m_queryCredsUiDisplayed = false;
671 
672  return;
673 }
674 
675 void SignonSessionCore::processUiRequest(const QString &cancelKey,
676  const QVariantMap &data)
677 {
678  TRACE();
679 
680  keepInUse();
681 
682  if (cancelKey != m_canceled && m_listOfRequests.size()) {
683  QString uiRequestId = m_listOfRequests.head().m_cancelKey;
684 
685  if (m_watcher) {
686  if (!m_watcher->isFinished())
687  m_signonui->cancelUiRequest(uiRequestId);
688 
689  delete m_watcher;
690  m_watcher = 0;
691  }
692 
693  m_listOfRequests.head().m_params = filterVariantMap(data);
694  m_listOfRequests.head().m_params[SSOUI_KEY_REQUESTID] = uiRequestId;
695 
696  if (m_id == SIGNOND_NEW_IDENTITY)
697  m_listOfRequests.head().m_params[SSOUI_KEY_STORED_IDENTITY] = false;
698  else
699  m_listOfRequests.head().m_params[SSOUI_KEY_STORED_IDENTITY] = true;
700  m_listOfRequests.head().m_params[SSOUI_KEY_IDENTITY] = m_id;
701  m_listOfRequests.head().m_params[SSOUI_KEY_CLIENT_DATA] = m_clientData;
702 
703  CredentialsAccessManager *camManager =
705  CredentialsDB *db = camManager->credentialsDB();
706  Q_ASSERT(db != 0);
707 
708  //check that we have caption
709  if (!data.contains(SSO_KEY_CAPTION)) {
710  TRACE() << "Caption missing";
711  if (m_id != SIGNOND_NEW_IDENTITY) {
712  SignonIdentityInfo info = db->credentials(m_id);
713  m_listOfRequests.head().m_params.insert(SSO_KEY_CAPTION,
714  info.caption());
715  TRACE() << "Got caption: " << info.caption();
716  }
717  }
718 
719  /*
720  * Check the secure storage status, if any issues are encountered signal
721  * this to the signon ui. */
722  if (!db->isSecretsDBOpen()) {
723  TRACE();
724 
725  //If there are no keys available
726  if (!camManager->keysAvailable()) {
727  TRACE() << "Secrets DB not available."
728  << "CAM has no keys available. Informing signon-ui.";
729  m_listOfRequests.head().m_params[
730  SSOUI_KEY_STORAGE_KEYS_UNAVAILABLE] = true;
731  }
732  }
733 
734  m_watcher = new QDBusPendingCallWatcher(
735  m_signonui->queryDialog(m_listOfRequests.head().m_params),
736  this);
737  connect(m_watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
738  this, SLOT(queryUiSlot(QDBusPendingCallWatcher*)));
739  }
740 }
741 
742 void SignonSessionCore::processRefreshRequest(const QString &cancelKey,
743  const QVariantMap &data)
744 {
745  TRACE();
746 
747  keepInUse();
748 
749  if (cancelKey != m_canceled && m_listOfRequests.size()) {
750  QString uiRequestId = m_listOfRequests.head().m_cancelKey;
751 
752  if (m_watcher) {
753  if (!m_watcher->isFinished())
754  m_signonui->cancelUiRequest(uiRequestId);
755 
756  delete m_watcher;
757  m_watcher = 0;
758  }
759 
760  m_listOfRequests.head().m_params = filterVariantMap(data);
761  m_watcher = new QDBusPendingCallWatcher(
762  m_signonui->refreshDialog(m_listOfRequests.head().m_params),
763  this);
764  connect(m_watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
765  this, SLOT(queryUiSlot(QDBusPendingCallWatcher*)));
766  }
767 }
768 
769 void SignonSessionCore::processError(const QString &cancelKey,
770  int err, const QString &message)
771 {
772  TRACE();
773  keepInUse();
774  m_tmpUsername.clear();
775  m_tmpPassword.clear();
776 
777  if (!m_listOfRequests.size())
778  return;
779 
780  RequestData rd = m_listOfRequests.dequeue();
781 
782  if (cancelKey != m_canceled) {
783  replyError(rd.m_conn, rd.m_msg, err, message);
784 
785  if (m_watcher && !m_watcher->isFinished()) {
786  m_signonui->cancelUiRequest(rd.m_cancelKey);
787  delete m_watcher;
788  m_watcher = 0;
789  }
790  }
791 
792  m_canceled = QString();
793  QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
794 }
795 
796 void SignonSessionCore::stateChangedSlot(const QString &cancelKey,
797  int state, const QString &message)
798 {
799  if (cancelKey != m_canceled && m_listOfRequests.size()) {
800  RequestData rd = m_listOfRequests.head();
801  emit stateChanged(rd.m_cancelKey, (int)state, message);
802  }
803 
804  keepInUse();
805 }
806 
807 void SignonSessionCore::childEvent(QChildEvent *ce)
808 {
809  if (ce->added())
810  keepInUse();
811  else if (ce->removed())
813 }
814 
816 {
817  /* TODO: This method is useless now, and there's probably a simpler
818  * way to handle the secure storage events than using QEvent (such
819  * as direct signal connections).
820  * For the time being, let this method live just for logging the
821  * secure storage events.
822  */
823  TRACE() << "Custom event received.";
824  if (event->type() == SIGNON_SECURE_STORAGE_AVAILABLE) {
825  TRACE() << "Secure storage is available.";
826  } else if (event->type() == SIGNON_SECURE_STORAGE_NOT_AVAILABLE) {
827  TRACE() << "Secure storage still not available.";
828  }
829 
830  QObject::customEvent(event);
831 }
832 
833 void SignonSessionCore::queryUiSlot(QDBusPendingCallWatcher *call)
834 {
835  keepInUse();
836 
837  QDBusPendingReply<QVariantMap> reply = *call;
838  bool isRequestToRefresh = false;
839  Q_ASSERT_X(m_listOfRequests.size() != 0, __func__,
840  "queue of requests is empty");
841 
842  if (!reply.isError() && reply.count()) {
843  QVariantMap resultParameters = reply.argumentAt<0>();
844  if (resultParameters.contains(SSOUI_KEY_REFRESH)) {
845  isRequestToRefresh = true;
846  resultParameters.remove(SSOUI_KEY_REFRESH);
847  }
848 
849  m_listOfRequests.head().m_params = resultParameters;
850 
851  /* If the query ui was canceled or any other error occurred
852  * do not set this flag to true. */
853  if (resultParameters.contains(SSOUI_KEY_ERROR)
854  && (resultParameters[SSOUI_KEY_ERROR] == QUERY_ERROR_CANCELED)) {
855 
856  m_queryCredsUiDisplayed = false;
857  } else {
858  m_queryCredsUiDisplayed = true;
859  }
860  } else {
861  m_listOfRequests.head().m_params.insert(SSOUI_KEY_ERROR,
862  (int)SignOn::QUERY_ERROR_NO_SIGNONUI);
863  }
864 
865  if (m_listOfRequests.head().m_cancelKey != m_canceled) {
866  /* Temporary caching, if credentials are valid
867  * this data will be effectively cached */
868  m_tmpUsername = m_listOfRequests.head().m_params.value(
869  SSO_KEY_USERNAME, QVariant()).toString();
870  m_tmpPassword = m_listOfRequests.head().m_params.value(
871  SSO_KEY_PASSWORD, QVariant()).toString();
872 
873  if (isRequestToRefresh) {
874  TRACE() << "REFRESH IS REQUIRED";
875 
876  m_listOfRequests.head().m_params.remove(SSOUI_KEY_REFRESH);
877  m_plugin->processRefresh(m_listOfRequests.head().m_cancelKey,
878  m_listOfRequests.head().m_params);
879  } else {
880  m_plugin->processUi(m_listOfRequests.head().m_cancelKey,
881  m_listOfRequests.head().m_params);
882  }
883  }
884 
885  delete m_watcher;
886  m_watcher = NULL;
887 }
888 
889 void SignonSessionCore::startNewRequest()
890 {
891  keepInUse();
892 
893  // there is no request
894  if (!m_listOfRequests.length()) {
895  TRACE() << "the data queue is EMPTY!!!";
896  return;
897  }
898 
899  //plugin is busy
900  if (m_plugin && m_plugin->isProcessing()) {
901  TRACE() << " the plugin is in challenge processing";
902  return;
903  }
904 
905  //there is some UI operation with plugin
906  if (m_watcher && !m_watcher->isFinished()) {
907  TRACE() << "watcher is in running mode";
908  return;
909  }
910 
911  TRACE() << "Start the authentication process";
912  startProcess();
913 }
914 
916 {
917  if (m_plugin->isProcessing() ||
918  m_watcher != NULL) {
919  keepInUse();
920  return;
921  }
922 
923  if (m_id)
924  sessionsOfStoredCredentials.remove(sessionName(m_id, m_method));
925  else
926  sessionsOfNonStoredCredentials.removeOne(this);
927 
928  emit destroyed();
929  deleteLater();
930 }
931 
933 {
934  QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
935 }