signon  8.48
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"
29 #include "signonui_interface.h"
31 
32 #include "SignOn/uisessiondata_priv.h"
33 #include "SignOn/authpluginif.h"
34 #include "SignOn/signonerror.h"
35 
36 #define MAX_IDLE_TIME SIGNOND_MAX_IDLE_TIME
37 /*
38  * the watchdog searches for idle sessions with period of half of idle timeout
39  * */
40 #define IDLE_WATCHDOG_TIMEOUT SIGNOND_MAX_IDLE_TIME * 500
41 
42 #define SSO_KEY_USERNAME QLatin1String("UserName")
43 #define SSO_KEY_PASSWORD QLatin1String("Secret")
44 #define SSO_KEY_CAPTION QLatin1String("Caption")
45 
46 using namespace SignonDaemonNS;
47 
48 /*
49  * cache of session queues, as was mentined they cannot be static
50  * */
52 /*
53  * List of "zero" authsessions, needed for global signout
54  * */
56 
57 static QVariantMap filterVariantMap(const QVariantMap &other)
58 {
59  QVariantMap result;
60 
61  foreach(QString key, other.keys()) {
62  if (!other.value(key).isNull() && other.value(key).isValid())
63  result.insert(key, other.value(key));
64  }
65 
66  return result;
67 }
68 
69 static QString sessionName(const quint32 id, const QString &method)
70 {
71  return QString::number(id) + QLatin1String("+") + method;
72 }
73 
75  const QString &method,
76  int timeout,
77  QObject *parent):
78  SignonDisposable(timeout, parent),
79  m_signonui(0),
80  m_watcher(0),
81  m_requestIsActive(false),
82  m_canceled(false),
83  m_id(id),
84  m_method(method),
85  m_queryCredsUiDisplayed(false)
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 key = sessionName(id, method);
113 
114  if (id) {
115  if (sessionsOfStoredCredentials.contains(key)) {
116  return sessionsOfStoredCredentials.value(key);
117  }
118  }
119 
120  SignonSessionCore *ssc = new SignonSessionCore(id, method,
121  parent->authSessionTimeout(),
122  parent);
123 
124  if (ssc->setupPlugin() == false) {
125  TRACE() << "The resulted object is corrupted and has to be deleted";
126  delete ssc;
127  return NULL;
128  }
129 
130  if (id)
131  sessionsOfStoredCredentials.insert(key, ssc);
132  else
133  sessionsOfNonStoredCredentials.append(ssc);
134 
135  TRACE() << "The new session is created :" << key;
136  return ssc;
137 }
138 
139 quint32 SignonSessionCore::id() const
140 {
141  TRACE();
142  keepInUse();
143  return m_id;
144 }
145 
147 {
148  TRACE();
149  keepInUse();
150  return m_method;
151 }
152 
154 {
155  m_plugin = PluginProxy::createNewPluginProxy(m_method);
156 
157  if (!m_plugin) {
158  TRACE() << "Plugin of type " << m_method << " cannot be found";
159  return false;
160  }
161 
162  connect(m_plugin,
163  SIGNAL(processResultReply(const QVariantMap&)),
164  this,
165  SLOT(processResultReply(const QVariantMap&)),
166  Qt::DirectConnection);
167 
168  connect(m_plugin,
169  SIGNAL(processStore(const QVariantMap&)),
170  this,
171  SLOT(processStore(const QVariantMap&)),
172  Qt::DirectConnection);
173 
174  connect(m_plugin,
175  SIGNAL(processUiRequest(const QVariantMap&)),
176  this,
177  SLOT(processUiRequest(const QVariantMap&)),
178  Qt::DirectConnection);
179 
180  connect(m_plugin,
181  SIGNAL(processRefreshRequest(const QVariantMap&)),
182  this,
183  SLOT(processRefreshRequest(const QVariantMap&)),
184  Qt::DirectConnection);
185 
186  connect(m_plugin,
187  SIGNAL(processError(int, const QString&)),
188  this,
189  SLOT(processError(int, const QString&)),
190  Qt::DirectConnection);
191 
192  connect(m_plugin,
193  SIGNAL(stateChanged(int, const QString&)),
194  this,
195  SLOT(stateChangedSlot(int, const QString&)),
196  Qt::DirectConnection);
197 
198  return true;
199 }
200 
202 {
203  qDeleteAll(sessionsOfStoredCredentials);
205 
206  qDeleteAll(sessionsOfNonStoredCredentials);
208 }
209 
210 QStringList SignonSessionCore::loadedPluginMethods(const QString &method)
211 {
212  foreach (SignonSessionCore *corePtr, sessionsOfStoredCredentials) {
213  if (corePtr->method() == method)
214  return corePtr->queryAvailableMechanisms(QStringList());
215  }
216 
218  if (corePtr->method() == method)
219  return corePtr->queryAvailableMechanisms(QStringList());
220  }
221 
222  return QStringList();
223 }
224 
225 QStringList
226 SignonSessionCore::queryAvailableMechanisms(const QStringList &wantedMechanisms)
227 {
228  keepInUse();
229 
230  if (!wantedMechanisms.size())
231  return m_plugin->mechanisms();
232 
233  return m_plugin->mechanisms().toSet().
234  intersect(wantedMechanisms.toSet()).toList();
235 }
236 
237 void SignonSessionCore::process(const QDBusConnection &connection,
238  const QDBusMessage &message,
239  const QVariantMap &sessionDataVa,
240  const QString &mechanism,
241  const QString &cancelKey)
242 {
243  keepInUse();
244  m_listOfRequests.enqueue(RequestData(connection,
245  message,
246  sessionDataVa,
247  mechanism,
248  cancelKey));
249 
250  if (CredentialsAccessManager::instance()->isCredentialsSystemReady())
251  QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
252 }
253 
254 void SignonSessionCore::cancel(const QString &cancelKey)
255 {
256  TRACE();
257 
258  int requestIndex;
259  for (requestIndex = 0;
260  requestIndex < m_listOfRequests.size();
261  requestIndex++) {
262  if (m_listOfRequests.at(requestIndex).m_cancelKey == cancelKey)
263  break;
264  }
265 
266  TRACE() << "The request is found with index " << requestIndex;
267 
268  if (requestIndex < m_listOfRequests.size()) {
269  /* If the request being cancelled is active, we need to keep
270  * in the queue until the plugin has replied. */
271  bool isActive = (requestIndex == 0) && m_requestIsActive;
272  if (isActive) {
273  m_canceled = true;
274  m_plugin->cancel();
275 
276  if (m_watcher && !m_watcher->isFinished()) {
277  m_signonui->cancelUiRequest(cancelKey);
278  delete m_watcher;
279  m_watcher = 0;
280  }
281  }
282 
283  /*
284  * We must let to the m_listOfRequests to have the canceled request data
285  * in order to delay the next request execution until the actual cancelation
286  * will happen. We will know about that precisely: plugin must reply via
287  * resultSlot or via errorSlot.
288  * */
289  RequestData rd(isActive ?
290  m_listOfRequests.head() :
291  m_listOfRequests.takeAt(requestIndex));
292 
293  QDBusMessage errReply =
294  rd.m_msg.createErrorReply(SIGNOND_SESSION_CANCELED_ERR_NAME,
295  SIGNOND_SESSION_CANCELED_ERR_STR);
296  rd.m_conn.send(errReply);
297  TRACE() << "Size of the queue is" << m_listOfRequests.size();
298  }
299 }
300 
301 void SignonSessionCore::setId(quint32 id)
302 {
303  keepInUse();
304 
305  if (m_id == id)
306  return;
307 
308  QString key;
309 
310  if (id == 0) {
311  key = sessionName(m_id, m_method);
313  sessionsOfStoredCredentials.take(key));
314  } else {
315  key = sessionName(id, m_method);
316  if (sessionsOfStoredCredentials.contains(key)) {
317  qCritical() << "attempt to assign existing id";
318  return;
319  }
320 
321  sessionsOfNonStoredCredentials.removeOne(this);
322  sessionsOfStoredCredentials[key] = this;
323  }
324  m_id = id;
325 }
326 
327 void SignonSessionCore::startProcess()
328 {
329 
330  TRACE() << "the number of requests is" << m_listOfRequests.length();
331 
332  m_requestIsActive = true;
333  RequestData data = m_listOfRequests.head();
334  QVariantMap parameters = data.m_params;
335 
336  /* save the client data; this should not be modified during the processing
337  * of this request */
338  m_clientData = parameters;
339 
340  if (m_id) {
341  CredentialsDB *db =
343  Q_ASSERT(db != 0);
344 
345  SignonIdentityInfo info = db->credentials(m_id);
346  if (info.id() != SIGNOND_NEW_IDENTITY) {
347  if (!parameters.contains(SSO_KEY_PASSWORD)) {
348  parameters[SSO_KEY_PASSWORD] = info.password();
349  }
350  //database overrules over sessiondata for validated username,
351  //so that identity cannot be misused
352  if (info.validated() || !parameters.contains(SSO_KEY_USERNAME)) {
353  parameters[SSO_KEY_USERNAME] = info.userName();
354  }
355 
356  QStringList paramsTokenList;
357  QStringList identityAclList = info.accessControlList();
358 
359  foreach(QString acl, identityAclList)
360  if (AccessControlManagerHelper::instance()->isPeerAllowedToAccess(data.m_msg, acl))
361  paramsTokenList.append(acl);
362 
363  if (!paramsTokenList.isEmpty()) {
364  parameters[SSO_ACCESS_CONTROL_TOKENS] = paramsTokenList;
365  }
366  } else {
367  BLAME() << "Error occurred while getting data from credentials "
368  "database.";
369  }
370 
371  QVariantMap storedParams = db->loadData(m_id, m_method);
372 
373  //parameters will overwrite any common keys on stored params
374  parameters = mergeVariantMaps(storedParams, parameters);
375  }
376 
377  if (parameters.contains(SSOUI_KEY_UIPOLICY)
378  && parameters[SSOUI_KEY_UIPOLICY] == RequestPasswordPolicy) {
379  parameters.remove(SSO_KEY_PASSWORD);
380  }
381 
382  /* Temporary caching, if credentials are valid
383  * this data will be effectively cached */
384  m_tmpUsername = parameters[SSO_KEY_USERNAME].toString();
385  m_tmpPassword = parameters[SSO_KEY_PASSWORD].toString();
386 
387  if (!m_plugin->process(parameters, data.m_mechanism)) {
388  QDBusMessage errReply =
389  data.m_msg.createErrorReply(SIGNOND_RUNTIME_ERR_NAME,
390  SIGNOND_RUNTIME_ERR_STR);
391  data.m_conn.send(errReply);
392  requestDone();
393  } else
394  stateChangedSlot(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::requestDone()
534 {
535  m_listOfRequests.removeFirst();
536  m_requestIsActive = false;
537  QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
538 }
539 
540 void SignonSessionCore::processResultReply(const QVariantMap &data)
541 {
542  TRACE();
543 
544  keepInUse();
545 
546  if (m_listOfRequests.isEmpty())
547  return;
548 
549  RequestData rd = m_listOfRequests.head();
550 
551  if (!m_canceled) {
552  QVariantList arguments;
553  QVariantMap filteredData = filterVariantMap(data);
554 
555  CredentialsAccessManager *camManager =
557  CredentialsDB *db = camManager->credentialsDB();
558  Q_ASSERT(db != 0);
559 
560  //update database entry
561  if (m_id != SIGNOND_NEW_IDENTITY) {
562  SignonIdentityInfo info = db->credentials(m_id);
563  bool identityWasValidated = info.validated();
564 
565  /* update username and password from ui interaction; do not allow
566  * updating the username if the identity is validated */
567  if (!info.validated() && !m_tmpUsername.isEmpty()) {
568  info.setUserName(m_tmpUsername);
569  }
570  if (!m_tmpPassword.isEmpty()) {
571  info.setPassword(m_tmpPassword);
572  }
573  info.setValidated(true);
574 
576  storeOp.m_info = info;
577  processStoreOperation(storeOp);
578 
579  /* If the credentials are validated, the secrets db is not
580  * available and not authorized keys are available, then
581  * the store operation has been performed on the memory
582  * cache only; inform the CAM about the situation. */
583  if (identityWasValidated && !db->isSecretsDBOpen()) {
584  /* Send the storage not available event only if the curent
585  * result processing is following a previous signon UI query.
586  * This is to avoid unexpected UI pop-ups. */
587 
588  if (m_queryCredsUiDisplayed) {
589  SecureStorageEvent *event =
590  new SecureStorageEvent(
592 
593  event->m_sender = static_cast<QObject *>(this);
594 
595  QCoreApplication::postEvent(
597  event,
598  Qt::HighEventPriority);
599  }
600  }
601  }
602 
603  m_tmpUsername.clear();
604  m_tmpPassword.clear();
605 
606  //remove secret field from output
607  if (m_method != QLatin1String("password")
608  && filteredData.contains(SSO_KEY_PASSWORD))
609  filteredData.remove(SSO_KEY_PASSWORD);
610 
611  arguments << filteredData;
612  rd.m_conn.send(rd.m_msg.createReply(arguments));
613 
614  if (m_watcher && !m_watcher->isFinished()) {
615  m_signonui->cancelUiRequest(rd.m_cancelKey);
616  delete m_watcher;
617  m_watcher = 0;
618  }
619  m_queryCredsUiDisplayed = false;
620  }
621 
622  requestDone();
623 }
624 
625 void SignonSessionCore::processStore(const QVariantMap &data)
626 {
627  TRACE();
628 
629  keepInUse();
630  if (m_id == SIGNOND_NEW_IDENTITY) {
631  BLAME() << "Cannot store without identity";
632  return;
633  }
634  QVariantMap filteredData = data;
635  //do not store username or password
636  filteredData.remove(SSO_KEY_PASSWORD);
637  filteredData.remove(SSO_KEY_USERNAME);
638  filteredData.remove(SSO_ACCESS_CONTROL_TOKENS);
639 
640  //store data into db
642  Q_ASSERT(db != NULL);
643 
645  storeOp.m_blobData = filteredData;
646  storeOp.m_authMethod = m_method;
647  processStoreOperation(storeOp);
648 
649  /* If the credentials are validated, the secrets db is not available and
650  * not authorized keys are available inform the CAM about the situation. */
651  SignonIdentityInfo info = db->credentials(m_id);
652  if (info.validated() && !db->isSecretsDBOpen()) {
653  /* Send the storage not available event only if the curent store
654  * processing is following a previous signon UI query. This is to avoid
655  * unexpected UI pop-ups.
656  */
657  if (m_queryCredsUiDisplayed) {
658  TRACE() << "Secure storage not available.";
659 
660  SecureStorageEvent *event =
661  new SecureStorageEvent(
663  event->m_sender = static_cast<QObject *>(this);
664 
665  QCoreApplication::postEvent(
667  event,
668  Qt::HighEventPriority);
669  }
670  }
671 
672  m_queryCredsUiDisplayed = false;
673 
674  return;
675 }
676 
677 void SignonSessionCore::processUiRequest(const QVariantMap &data)
678 {
679  TRACE();
680 
681  keepInUse();
682 
683  if (!m_canceled && !m_listOfRequests.isEmpty()) {
684  RequestData &request = m_listOfRequests.head();
685  QString uiRequestId = request.m_cancelKey;
686 
687  if (m_watcher) {
688  if (!m_watcher->isFinished())
689  m_signonui->cancelUiRequest(uiRequestId);
690 
691  delete m_watcher;
692  m_watcher = 0;
693  }
694 
695  request.m_params = filterVariantMap(data);
696  request.m_params[SSOUI_KEY_REQUESTID] = uiRequestId;
697 
698  if (m_id == SIGNOND_NEW_IDENTITY)
699  request.m_params[SSOUI_KEY_STORED_IDENTITY] = false;
700  else
701  request.m_params[SSOUI_KEY_STORED_IDENTITY] = true;
702  request.m_params[SSOUI_KEY_IDENTITY] = m_id;
703  request.m_params[SSOUI_KEY_CLIENT_DATA] = m_clientData;
704  request.m_params[SSOUI_KEY_METHOD] = m_method;
705  request.m_params[SSOUI_KEY_MECHANISM] = request.m_mechanism;
706 
707  CredentialsAccessManager *camManager =
709  CredentialsDB *db = camManager->credentialsDB();
710  Q_ASSERT(db != 0);
711 
712  //check that we have caption
713  if (!data.contains(SSO_KEY_CAPTION)) {
714  TRACE() << "Caption missing";
715  if (m_id != SIGNOND_NEW_IDENTITY) {
716  SignonIdentityInfo info = db->credentials(m_id);
717  request.m_params.insert(SSO_KEY_CAPTION, info.caption());
718  TRACE() << "Got caption: " << info.caption();
719  }
720  }
721 
722  /*
723  * Check the secure storage status, if any issues are encountered signal
724  * this to the signon ui. */
725  if (!db->isSecretsDBOpen()) {
726  TRACE();
727 
728  //If there are no keys available
729  if (!camManager->keysAvailable()) {
730  TRACE() << "Secrets DB not available."
731  << "CAM has no keys available. Informing signon-ui.";
732  request.m_params[SSOUI_KEY_STORAGE_KEYS_UNAVAILABLE] = true;
733  }
734  }
735 
736  m_watcher = new QDBusPendingCallWatcher(
737  m_signonui->queryDialog(request.m_params),
738  this);
739  connect(m_watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
740  this, SLOT(queryUiSlot(QDBusPendingCallWatcher*)));
741  }
742 }
743 
744 void SignonSessionCore::processRefreshRequest(const QVariantMap &data)
745 {
746  TRACE();
747 
748  keepInUse();
749 
750  if (!m_canceled && !m_listOfRequests.isEmpty()) {
751  QString uiRequestId = m_listOfRequests.head().m_cancelKey;
752 
753  if (m_watcher) {
754  if (!m_watcher->isFinished())
755  m_signonui->cancelUiRequest(uiRequestId);
756 
757  delete m_watcher;
758  m_watcher = 0;
759  }
760 
761  m_listOfRequests.head().m_params = filterVariantMap(data);
762  m_watcher = new QDBusPendingCallWatcher(
763  m_signonui->refreshDialog(m_listOfRequests.head().m_params),
764  this);
765  connect(m_watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
766  this, SLOT(queryUiSlot(QDBusPendingCallWatcher*)));
767  }
768 }
769 
770 void SignonSessionCore::processError(int err, const QString &message)
771 {
772  TRACE();
773  keepInUse();
774  m_tmpUsername.clear();
775  m_tmpPassword.clear();
776 
777  if (m_listOfRequests.isEmpty())
778  return;
779 
780  RequestData rd = m_listOfRequests.head();
781 
782  if (!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  requestDone();
793 }
794 
795 void SignonSessionCore::stateChangedSlot(int state, const QString &message)
796 {
797  if (!m_canceled && !m_listOfRequests.isEmpty()) {
798  RequestData rd = m_listOfRequests.head();
799  emit stateChanged(rd.m_cancelKey, (int)state, message);
800  }
801 
802  keepInUse();
803 }
804 
805 void SignonSessionCore::childEvent(QChildEvent *ce)
806 {
807  if (ce->added())
808  keepInUse();
809  else if (ce->removed())
811 }
812 
814 {
815  /* TODO: This method is useless now, and there's probably a simpler
816  * way to handle the secure storage events than using QEvent (such
817  * as direct signal connections).
818  * For the time being, let this method live just for logging the
819  * secure storage events.
820  */
821  TRACE() << "Custom event received.";
822  if (event->type() == SIGNON_SECURE_STORAGE_AVAILABLE) {
823  TRACE() << "Secure storage is available.";
824  } else if (event->type() == SIGNON_SECURE_STORAGE_NOT_AVAILABLE) {
825  TRACE() << "Secure storage still not available.";
826  }
827 
828  QObject::customEvent(event);
829 }
830 
831 void SignonSessionCore::queryUiSlot(QDBusPendingCallWatcher *call)
832 {
833  keepInUse();
834 
835  QDBusPendingReply<QVariantMap> reply = *call;
836  bool isRequestToRefresh = false;
837  Q_ASSERT_X(m_listOfRequests.size() != 0, __func__,
838  "queue of requests is empty");
839 
840  RequestData &rd = m_listOfRequests.head();
841  if (!reply.isError() && reply.count()) {
842  QVariantMap resultParameters = reply.argumentAt<0>();
843  if (resultParameters.contains(SSOUI_KEY_REFRESH)) {
844  isRequestToRefresh = true;
845  resultParameters.remove(SSOUI_KEY_REFRESH);
846  }
847 
848  rd.m_params = resultParameters;
849 
850  /* If the query ui was canceled or any other error occurred
851  * do not set this flag to true. */
852  if (resultParameters.contains(SSOUI_KEY_ERROR)
853  && (resultParameters[SSOUI_KEY_ERROR] == QUERY_ERROR_CANCELED)) {
854 
855  m_queryCredsUiDisplayed = false;
856  } else {
857  m_queryCredsUiDisplayed = true;
858  }
859  } else {
860  rd.m_params.insert(SSOUI_KEY_ERROR,
861  (int)SignOn::QUERY_ERROR_NO_SIGNONUI);
862  }
863 
864  if (!m_canceled) {
865  /* Temporary caching, if credentials are valid
866  * this data will be effectively cached */
867  m_tmpUsername = rd.m_params.value(SSO_KEY_USERNAME,
868  QVariant()).toString();
869  m_tmpPassword = rd.m_params.value(SSO_KEY_PASSWORD,
870  QVariant()).toString();
871 
872  if (isRequestToRefresh) {
873  TRACE() << "REFRESH IS REQUIRED";
874 
875  rd.m_params.remove(SSOUI_KEY_REFRESH);
876  m_plugin->processRefresh(rd.m_params);
877  } else {
878  m_plugin->processUi(rd.m_params);
879  }
880  }
881 
882  delete m_watcher;
883  m_watcher = NULL;
884 }
885 
886 void SignonSessionCore::startNewRequest()
887 {
888  keepInUse();
889 
890  m_canceled = false;
891 
892  if (m_listOfRequests.isEmpty()) {
893  TRACE() << "No more requests to process";
894  setAutoDestruct(true);
895  return;
896  }
897 
898  // there is an active request already
899  if (m_requestIsActive) {
900  TRACE() << "One request is already active";
901  return;
902  }
903 
904  //there is some UI operation with plugin
905  if (m_watcher && !m_watcher->isFinished()) {
906  TRACE() << "Some UI operation is still pending";
907  return;
908  }
909 
910  TRACE() << "Starting the authentication process";
911  setAutoDestruct(false);
912  startProcess();
913 }
914 
916 {
917  if (m_requestIsActive ||
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 }