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