signon  8.56
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) {
361  isPeerAllowedToAccess(data.m_conn, data.m_msg, acl))
362  paramsTokenList.append(acl);
363  }
364 
365  if (!paramsTokenList.isEmpty()) {
366  parameters[SSO_ACCESS_CONTROL_TOKENS] = paramsTokenList;
367  }
368  } else {
369  BLAME() << "Error occurred while getting data from credentials "
370  "database.";
371  }
372 
373  QVariantMap storedParams = db->loadData(m_id, m_method);
374 
375  //parameters will overwrite any common keys on stored params
376  parameters = mergeVariantMaps(storedParams, parameters);
377  }
378 
379  if (parameters.contains(SSOUI_KEY_UIPOLICY)
380  && parameters[SSOUI_KEY_UIPOLICY] == RequestPasswordPolicy) {
381  parameters.remove(SSO_KEY_PASSWORD);
382  }
383 
384  /* Temporary caching, if credentials are valid
385  * this data will be effectively cached */
386  m_tmpUsername = parameters[SSO_KEY_USERNAME].toString();
387  m_tmpPassword = parameters[SSO_KEY_PASSWORD].toString();
388 
389  if (!m_plugin->process(parameters, data.m_mechanism)) {
390  QDBusMessage errReply =
391  data.m_msg.createErrorReply(SIGNOND_RUNTIME_ERR_NAME,
392  SIGNOND_RUNTIME_ERR_STR);
393  data.m_conn.send(errReply);
394  requestDone();
395  } else
396  stateChangedSlot(SignOn::SessionStarted,
397  QLatin1String("The request is started successfully"));
398 }
399 
400 void SignonSessionCore::replyError(const QDBusConnection &conn,
401  const QDBusMessage &msg,
402  int err, const QString &message)
403 {
404  keepInUse();
405 
406  QString errName;
407  QString errMessage;
408 
409  //TODO this is needed for old error codes
410  if( err < Error::AuthSessionErr) {
411  BLAME() << "Deprecated error code:" << err;
412  if (message.isEmpty())
413  errMessage = SIGNOND_UNKNOWN_ERR_STR;
414  else
415  errMessage = message;
416  errName = SIGNOND_UNKNOWN_ERR_NAME;
417  }
418 
419  if (Error::AuthSessionErr < err && err < Error::UserErr) {
420  switch(err) {
421  case Error::MechanismNotAvailable:
422  errName = SIGNOND_MECHANISM_NOT_AVAILABLE_ERR_NAME;
423  errMessage = SIGNOND_MECHANISM_NOT_AVAILABLE_ERR_STR;
424  break;
425  case Error::MissingData:
426  errName = SIGNOND_MISSING_DATA_ERR_NAME;
427  errMessage = SIGNOND_MISSING_DATA_ERR_STR;
428  break;
429  case Error::InvalidCredentials:
430  errName = SIGNOND_INVALID_CREDENTIALS_ERR_NAME;
431  errMessage = SIGNOND_INVALID_CREDENTIALS_ERR_STR;
432  break;
433  case Error::NotAuthorized:
434  errName = SIGNOND_NOT_AUTHORIZED_ERR_NAME;
435  errMessage = SIGNOND_NOT_AUTHORIZED_ERR_STR;
436  break;
437  case Error::WrongState:
438  errName = SIGNOND_WRONG_STATE_ERR_NAME;
439  errMessage = SIGNOND_WRONG_STATE_ERR_STR;
440  break;
441  case Error::OperationNotSupported:
442  errName = SIGNOND_OPERATION_NOT_SUPPORTED_ERR_NAME;
443  errMessage = SIGNOND_OPERATION_NOT_SUPPORTED_ERR_STR;
444  break;
445  case Error::NoConnection:
446  errName = SIGNOND_NO_CONNECTION_ERR_NAME;
447  errMessage = SIGNOND_NO_CONNECTION_ERR_STR;
448  break;
449  case Error::Network:
450  errName = SIGNOND_NETWORK_ERR_NAME;
451  errMessage = SIGNOND_NETWORK_ERR_STR;
452  break;
453  case Error::Ssl:
454  errName = SIGNOND_SSL_ERR_NAME;
455  errMessage = SIGNOND_SSL_ERR_STR;
456  break;
457  case Error::Runtime:
458  errName = SIGNOND_RUNTIME_ERR_NAME;
459  errMessage = SIGNOND_RUNTIME_ERR_STR;
460  break;
461  case Error::SessionCanceled:
462  errName = SIGNOND_SESSION_CANCELED_ERR_NAME;
463  errMessage = SIGNOND_SESSION_CANCELED_ERR_STR;
464  break;
465  case Error::TimedOut:
466  errName = SIGNOND_TIMED_OUT_ERR_NAME;
467  errMessage = SIGNOND_TIMED_OUT_ERR_STR;
468  break;
469  case Error::UserInteraction:
470  errName = SIGNOND_USER_INTERACTION_ERR_NAME;
471  errMessage = SIGNOND_USER_INTERACTION_ERR_STR;
472  break;
473  case Error::OperationFailed:
474  errName = SIGNOND_OPERATION_FAILED_ERR_NAME;
475  errMessage = SIGNOND_OPERATION_FAILED_ERR_STR;
476  break;
477  case Error::EncryptionFailure:
478  errName = SIGNOND_ENCRYPTION_FAILED_ERR_NAME;
479  errMessage = SIGNOND_ENCRYPTION_FAILED_ERR_STR;
480  break;
481  case Error::TOSNotAccepted:
482  errName = SIGNOND_TOS_NOT_ACCEPTED_ERR_NAME;
483  errMessage = SIGNOND_TOS_NOT_ACCEPTED_ERR_STR;
484  break;
485  case Error::ForgotPassword:
486  errName = SIGNOND_FORGOT_PASSWORD_ERR_NAME;
487  errMessage = SIGNOND_FORGOT_PASSWORD_ERR_STR;
488  break;
489  case Error::IncorrectDate:
490  errName = SIGNOND_INCORRECT_DATE_ERR_NAME;
491  errMessage = SIGNOND_INCORRECT_DATE_ERR_STR;
492  break;
493  default:
494  if (message.isEmpty())
495  errMessage = SIGNOND_UNKNOWN_ERR_STR;
496  else
497  errMessage = message;
498  errName = SIGNOND_UNKNOWN_ERR_NAME;
499  break;
500  };
501  }
502 
503  if (err > Error::UserErr) {
504  errName = SIGNOND_USER_ERROR_ERR_NAME;
505  errMessage = (QString::fromLatin1("%1:%2")).arg(err).arg(message);
506  }
507 
508  QDBusMessage errReply;
509  errReply = msg.createErrorReply(errName,
510  (message.isEmpty() ? errMessage : message));
511  conn.send(errReply);
512 }
513 
514 void SignonSessionCore::processStoreOperation(const StoreOperation &operation)
515 {
516  TRACE() << "Processing store operation.";
518  Q_ASSERT(db != 0);
519 
520  if (operation.m_storeType != StoreOperation::Blob) {
521  if (!(db->updateCredentials(operation.m_info))) {
522  BLAME() << "Error occured while updating credentials.";
523  }
524  } else {
525  TRACE() << "Processing --- StoreOperation::Blob";
526 
527  if (!db->storeData(m_id,
528  operation.m_authMethod,
529  operation.m_blobData)) {
530  BLAME() << "Error occured while storing data.";
531  }
532  }
533 }
534 
535 void SignonSessionCore::requestDone()
536 {
537  m_listOfRequests.removeFirst();
538  m_requestIsActive = false;
539  QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
540 }
541 
542 void SignonSessionCore::processResultReply(const QVariantMap &data)
543 {
544  TRACE();
545 
546  keepInUse();
547 
548  if (m_listOfRequests.isEmpty())
549  return;
550 
551  RequestData rd = m_listOfRequests.head();
552 
553  if (!m_canceled) {
554  QVariantList arguments;
555  QVariantMap filteredData = filterVariantMap(data);
556 
557  CredentialsAccessManager *camManager =
559  CredentialsDB *db = camManager->credentialsDB();
560  Q_ASSERT(db != 0);
561 
562  //update database entry
563  if (m_id != SIGNOND_NEW_IDENTITY) {
564  SignonIdentityInfo info = db->credentials(m_id);
565  bool identityWasValidated = info.validated();
566 
567  /* update username and password from ui interaction; do not allow
568  * updating the username if the identity is validated */
569  if (!info.validated() && !m_tmpUsername.isEmpty()) {
570  info.setUserName(m_tmpUsername);
571  }
572  if (!m_tmpPassword.isEmpty()) {
573  info.setPassword(m_tmpPassword);
574  }
575  info.setValidated(true);
576 
578  storeOp.m_info = info;
579  processStoreOperation(storeOp);
580 
581  /* If the credentials are validated, the secrets db is not
582  * available and not authorized keys are available, then
583  * the store operation has been performed on the memory
584  * cache only; inform the CAM about the situation. */
585  if (identityWasValidated && !db->isSecretsDBOpen()) {
586  /* Send the storage not available event only if the curent
587  * result processing is following a previous signon UI query.
588  * This is to avoid unexpected UI pop-ups. */
589 
590  if (m_queryCredsUiDisplayed) {
591  SecureStorageEvent *event =
592  new SecureStorageEvent(
594 
595  event->m_sender = static_cast<QObject *>(this);
596 
597  QCoreApplication::postEvent(
599  event,
600  Qt::HighEventPriority);
601  }
602  }
603  }
604 
605  m_tmpUsername.clear();
606  m_tmpPassword.clear();
607 
608  //remove secret field from output
609  if (m_method != QLatin1String("password")
610  && filteredData.contains(SSO_KEY_PASSWORD))
611  filteredData.remove(SSO_KEY_PASSWORD);
612 
613  arguments << filteredData;
614  rd.m_conn.send(rd.m_msg.createReply(arguments));
615 
616  if (m_watcher && !m_watcher->isFinished()) {
617  m_signonui->cancelUiRequest(rd.m_cancelKey);
618  delete m_watcher;
619  m_watcher = 0;
620  }
621  m_queryCredsUiDisplayed = false;
622  }
623 
624  requestDone();
625 }
626 
627 void SignonSessionCore::processStore(const QVariantMap &data)
628 {
629  TRACE();
630 
631  keepInUse();
632  if (m_id == SIGNOND_NEW_IDENTITY) {
633  BLAME() << "Cannot store without identity";
634  return;
635  }
636  QVariantMap filteredData = data;
637  //do not store username or password
638  filteredData.remove(SSO_KEY_PASSWORD);
639  filteredData.remove(SSO_KEY_USERNAME);
640  filteredData.remove(SSO_ACCESS_CONTROL_TOKENS);
641 
642  //store data into db
644  Q_ASSERT(db != NULL);
645 
647  storeOp.m_blobData = filteredData;
648  storeOp.m_authMethod = m_method;
649  processStoreOperation(storeOp);
650 
651  /* If the credentials are validated, the secrets db is not available and
652  * not authorized keys are available inform the CAM about the situation. */
653  SignonIdentityInfo info = db->credentials(m_id);
654  if (info.validated() && !db->isSecretsDBOpen()) {
655  /* Send the storage not available event only if the curent store
656  * processing is following a previous signon UI query. This is to avoid
657  * unexpected UI pop-ups.
658  */
659  if (m_queryCredsUiDisplayed) {
660  TRACE() << "Secure storage not available.";
661 
662  SecureStorageEvent *event =
663  new SecureStorageEvent(
665  event->m_sender = static_cast<QObject *>(this);
666 
667  QCoreApplication::postEvent(
669  event,
670  Qt::HighEventPriority);
671  }
672  }
673 
674  m_queryCredsUiDisplayed = false;
675 
676  return;
677 }
678 
679 void SignonSessionCore::processUiRequest(const QVariantMap &data)
680 {
681  TRACE();
682 
683  keepInUse();
684 
685  if (!m_canceled && !m_listOfRequests.isEmpty()) {
686  RequestData &request = m_listOfRequests.head();
687  QString uiRequestId = request.m_cancelKey;
688 
689  if (m_watcher) {
690  if (!m_watcher->isFinished())
691  m_signonui->cancelUiRequest(uiRequestId);
692 
693  delete m_watcher;
694  m_watcher = 0;
695  }
696 
697  request.m_params = filterVariantMap(data);
698  request.m_params[SSOUI_KEY_REQUESTID] = uiRequestId;
699 
700  if (m_id == SIGNOND_NEW_IDENTITY)
701  request.m_params[SSOUI_KEY_STORED_IDENTITY] = false;
702  else
703  request.m_params[SSOUI_KEY_STORED_IDENTITY] = true;
704  request.m_params[SSOUI_KEY_IDENTITY] = m_id;
705  request.m_params[SSOUI_KEY_CLIENT_DATA] = m_clientData;
706  request.m_params[SSOUI_KEY_METHOD] = m_method;
707  request.m_params[SSOUI_KEY_MECHANISM] = request.m_mechanism;
708 
709  CredentialsAccessManager *camManager =
711  CredentialsDB *db = camManager->credentialsDB();
712  Q_ASSERT(db != 0);
713 
714  //check that we have caption
715  if (!data.contains(SSO_KEY_CAPTION)) {
716  TRACE() << "Caption missing";
717  if (m_id != SIGNOND_NEW_IDENTITY) {
718  SignonIdentityInfo info = db->credentials(m_id);
719  request.m_params.insert(SSO_KEY_CAPTION, info.caption());
720  TRACE() << "Got caption: " << info.caption();
721  }
722  }
723 
724  /*
725  * Check the secure storage status, if any issues are encountered signal
726  * this to the signon ui. */
727  if (!db->isSecretsDBOpen()) {
728  TRACE();
729 
730  //If there are no keys available
731  if (!camManager->keysAvailable()) {
732  TRACE() << "Secrets DB not available."
733  << "CAM has no keys available. Informing signon-ui.";
734  request.m_params[SSOUI_KEY_STORAGE_KEYS_UNAVAILABLE] = true;
735  }
736  }
737 
738  m_watcher = new QDBusPendingCallWatcher(
739  m_signonui->queryDialog(request.m_params),
740  this);
741  connect(m_watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
742  this, SLOT(queryUiSlot(QDBusPendingCallWatcher*)));
743  }
744 }
745 
746 void SignonSessionCore::processRefreshRequest(const QVariantMap &data)
747 {
748  TRACE();
749 
750  keepInUse();
751 
752  if (!m_canceled && !m_listOfRequests.isEmpty()) {
753  QString uiRequestId = m_listOfRequests.head().m_cancelKey;
754 
755  if (m_watcher) {
756  if (!m_watcher->isFinished())
757  m_signonui->cancelUiRequest(uiRequestId);
758 
759  delete m_watcher;
760  m_watcher = 0;
761  }
762 
763  m_listOfRequests.head().m_params = filterVariantMap(data);
764  m_watcher = new QDBusPendingCallWatcher(
765  m_signonui->refreshDialog(m_listOfRequests.head().m_params),
766  this);
767  connect(m_watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
768  this, SLOT(queryUiSlot(QDBusPendingCallWatcher*)));
769  }
770 }
771 
772 void SignonSessionCore::processError(int err, const QString &message)
773 {
774  TRACE();
775  keepInUse();
776  m_tmpUsername.clear();
777  m_tmpPassword.clear();
778 
779  if (m_listOfRequests.isEmpty())
780  return;
781 
782  RequestData rd = m_listOfRequests.head();
783 
784  if (!m_canceled) {
785  replyError(rd.m_conn, rd.m_msg, err, message);
786 
787  if (m_watcher && !m_watcher->isFinished()) {
788  m_signonui->cancelUiRequest(rd.m_cancelKey);
789  delete m_watcher;
790  m_watcher = 0;
791  }
792  }
793 
794  requestDone();
795 }
796 
797 void SignonSessionCore::stateChangedSlot(int state, const QString &message)
798 {
799  if (!m_canceled && !m_listOfRequests.isEmpty()) {
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  RequestData &rd = m_listOfRequests.head();
843  if (!reply.isError() && reply.count()) {
844  QVariantMap resultParameters = reply.argumentAt<0>();
845  if (resultParameters.contains(SSOUI_KEY_REFRESH)) {
846  isRequestToRefresh = true;
847  resultParameters.remove(SSOUI_KEY_REFRESH);
848  }
849 
850  rd.m_params = resultParameters;
851 
852  /* If the query ui was canceled or any other error occurred
853  * do not set this flag to true. */
854  if (resultParameters.contains(SSOUI_KEY_ERROR)
855  && (resultParameters[SSOUI_KEY_ERROR] == QUERY_ERROR_CANCELED)) {
856 
857  m_queryCredsUiDisplayed = false;
858  } else {
859  m_queryCredsUiDisplayed = true;
860  }
861  } else {
862  rd.m_params.insert(SSOUI_KEY_ERROR,
863  (int)SignOn::QUERY_ERROR_NO_SIGNONUI);
864  }
865 
866  if (!m_canceled) {
867  /* Temporary caching, if credentials are valid
868  * this data will be effectively cached */
869  m_tmpUsername = rd.m_params.value(SSO_KEY_USERNAME,
870  QVariant()).toString();
871  m_tmpPassword = rd.m_params.value(SSO_KEY_PASSWORD,
872  QVariant()).toString();
873 
874  if (isRequestToRefresh) {
875  TRACE() << "REFRESH IS REQUIRED";
876 
877  rd.m_params.remove(SSOUI_KEY_REFRESH);
878  m_plugin->processRefresh(rd.m_params);
879  } else {
880  m_plugin->processUi(rd.m_params);
881  }
882  }
883 
884  delete m_watcher;
885  m_watcher = NULL;
886 }
887 
888 void SignonSessionCore::startNewRequest()
889 {
890  keepInUse();
891 
892  m_canceled = false;
893 
894  if (m_listOfRequests.isEmpty()) {
895  TRACE() << "No more requests to process";
896  setAutoDestruct(true);
897  return;
898  }
899 
900  // there is an active request already
901  if (m_requestIsActive) {
902  TRACE() << "One request is already active";
903  return;
904  }
905 
906  //there is some UI operation with plugin
907  if (m_watcher && !m_watcher->isFinished()) {
908  TRACE() << "Some UI operation is still pending";
909  return;
910  }
911 
912  TRACE() << "Starting the authentication process";
913  setAutoDestruct(false);
914  startProcess();
915 }
916 
918 {
919  if (m_requestIsActive ||
920  m_watcher != NULL) {
921  keepInUse();
922  return;
923  }
924 
925  if (m_id)
926  sessionsOfStoredCredentials.remove(sessionName(m_id, m_method));
927  else
928  sessionsOfNonStoredCredentials.removeOne(this);
929 
930  QObjectList authSessions;
931  while (authSessions = children(), !authSessions.isEmpty()) {
932  delete authSessions.first();
933  }
934  deleteLater();
935 }
936 
938 {
939  QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
940 }
void process(const QDBusConnection &connection, const QDBusMessage &message, const QVariantMap &sessionDataVa, const QString &mechanism, const QString &cancelKey)
static PluginProxy * createNewPluginProxy(const QString &type)
QList< SignonSessionCore * > sessionsOfNonStoredCredentials
Base class for server objects that can be automatically destroyed after a certain period of inactivit...
bool processRefresh(const QVariantMap &inData)
Describes a credentials store operatation.
Daemon side representation of authentication session.
#define BLAME()
Definition: debug.h:32
static AccessControlManagerHelper * instance()
#define SSO_KEY_CAPTION
void destroy()
Performs any predestruction operations and the destruction itself.
quint32 updateCredentials(const SignonIdentityInfo &info)
bool process(const QVariantMap &inData, const QString &mechanism)
bool storeData(const quint32 id, const QString &method, const QVariantMap &data)
QMap< QString, SignonSessionCore * > sessionsOfStoredCredentials
QDBusPendingCall refreshDialog(const QVariantMap &parameters)
Any object in the signon framework that needs the CredentialsAccessManager - CAM - secure storage in ...
QVariantMap loadData(const quint32 id, const QString &method)
static void destroyUnused()
Deletes all disposable object for which the inactivity time has elapsed.
void stateChanged(const QString &requestId, int state, const QString &message)
static CredentialsAccessManager * instance()
Returns CAM instance.
#define SIGNON_UI_SERVICE
void setPassword(const QString &password)
QStringList queryAvailableMechanisms(const QStringList &wantedMechanisms)
#define SIGNON_SECURE_STORAGE_AVAILABLE
The CAM will reply with an event of this type when the secure storage access will be successfully res...
SignonIdentityInfo credentials(const quint32 id, bool queryPassword=true)
QStringList mechanisms() const
Definition: pluginproxy.h:72
void cancelUiRequest(const QString &requestId)
#define SSO_KEY_PASSWORD
Main singleton and manager object of the credentials database system.
#define SIGNON_SECURE_STORAGE_NOT_AVAILABLE
Use this event type to signal the CAM when the secure storage is not available.
QDBusPendingCall queryDialog(const QVariantMap &parameters)
bool processUi(const QVariantMap &inData)
static SignonSessionCore * sessionCore(const quint32 id, const QString &method, SignonDaemon *parent)
bool keysAvailable() const
The CAM manages the encryption keys collection.
#define TRACE()
Definition: debug.h:28
static QStringList loadedPluginMethods(const QString &method)
QVariantMap mergeVariantMaps(const QVariantMap &map1, const QVariantMap &map2)
Helper method which unites two variant maps.
Daemon side representation of identity information.
Manages the credentials I/O.
Definition: credentialsdb.h:66
Helper class for access control-related functionality.
#define SIGNON_UI_DAEMON_OBJECTPATH
void setUserName(const QString &userName)
void setAutoDestruct(bool value=true) const
Mark the object as used.
#define SSO_KEY_USERNAME
void keepInUse() const
Mark the object as used.
void cancel(const QString &cancelKey)
SignonSessionCore(quint32 id, const QString &method, int timeout, QObject *parent)