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