signon  8.58
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);
204  sessionsOfStoredCredentials.clear();
205 
206  qDeleteAll(sessionsOfNonStoredCredentials);
207  sessionsOfNonStoredCredentials.clear();
208 }
209 
211 {
212  foreach (SignonSessionCore *corePtr, sessionsOfStoredCredentials) {
213  if (corePtr->method() == method)
214  return corePtr->queryAvailableMechanisms(QStringList());
215  }
216 
217  foreach (SignonSessionCore *corePtr, sessionsOfNonStoredCredentials) {
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);
312  sessionsOfNonStoredCredentials.append(
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  /* Pass some data about the requesting client */
711  request.m_params[SSOUI_KEY_PID] = acm->pidOfPeer(request.m_conn,
712  request.m_msg);
713  request.m_params[SSOUI_KEY_APP_ID] = acm->appIdOfPeer(request.m_conn,
714  request.m_msg);
715 
716  CredentialsAccessManager *camManager =
718  CredentialsDB *db = camManager->credentialsDB();
719  Q_ASSERT(db != 0);
720 
721  //check that we have caption
722  if (!data.contains(SSO_KEY_CAPTION)) {
723  TRACE() << "Caption missing";
724  if (m_id != SIGNOND_NEW_IDENTITY) {
725  SignonIdentityInfo info = db->credentials(m_id);
726  request.m_params.insert(SSO_KEY_CAPTION, info.caption());
727  TRACE() << "Got caption: " << info.caption();
728  }
729  }
730 
731  /*
732  * Check the secure storage status, if any issues are encountered signal
733  * this to the signon ui. */
734  if (!db->isSecretsDBOpen()) {
735  TRACE();
736 
737  //If there are no keys available
738  if (!camManager->keysAvailable()) {
739  TRACE() << "Secrets DB not available."
740  << "CAM has no keys available. Informing signon-ui.";
741  request.m_params[SSOUI_KEY_STORAGE_KEYS_UNAVAILABLE] = true;
742  }
743  }
744 
745  m_watcher = new QDBusPendingCallWatcher(
746  m_signonui->queryDialog(request.m_params),
747  this);
748  connect(m_watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
749  this, SLOT(queryUiSlot(QDBusPendingCallWatcher*)));
750  }
751 }
752 
753 void SignonSessionCore::processRefreshRequest(const QVariantMap &data)
754 {
755  TRACE();
756 
757  keepInUse();
758 
759  if (!m_canceled && !m_listOfRequests.isEmpty()) {
760  QString uiRequestId = m_listOfRequests.head().m_cancelKey;
761 
762  if (m_watcher) {
763  if (!m_watcher->isFinished())
764  m_signonui->cancelUiRequest(uiRequestId);
765 
766  delete m_watcher;
767  m_watcher = 0;
768  }
769 
770  m_listOfRequests.head().m_params = filterVariantMap(data);
771  m_watcher = new QDBusPendingCallWatcher(
772  m_signonui->refreshDialog(m_listOfRequests.head().m_params),
773  this);
774  connect(m_watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
775  this, SLOT(queryUiSlot(QDBusPendingCallWatcher*)));
776  }
777 }
778 
779 void SignonSessionCore::processError(int err, const QString &message)
780 {
781  TRACE();
782  keepInUse();
783  m_tmpUsername.clear();
784  m_tmpPassword.clear();
785 
786  if (m_listOfRequests.isEmpty())
787  return;
788 
789  RequestData rd = m_listOfRequests.head();
790 
791  if (!m_canceled) {
792  replyError(rd.m_conn, rd.m_msg, err, message);
793 
794  if (m_watcher && !m_watcher->isFinished()) {
795  m_signonui->cancelUiRequest(rd.m_cancelKey);
796  delete m_watcher;
797  m_watcher = 0;
798  }
799  }
800 
801  requestDone();
802 }
803 
804 void SignonSessionCore::stateChangedSlot(int state, const QString &message)
805 {
806  if (!m_canceled && !m_listOfRequests.isEmpty()) {
807  RequestData rd = m_listOfRequests.head();
808  emit stateChanged(rd.m_cancelKey, (int)state, message);
809  }
810 
811  keepInUse();
812 }
813 
814 void SignonSessionCore::childEvent(QChildEvent *ce)
815 {
816  if (ce->added())
817  keepInUse();
818  else if (ce->removed())
820 }
821 
823 {
824  /* TODO: This method is useless now, and there's probably a simpler
825  * way to handle the secure storage events than using QEvent (such
826  * as direct signal connections).
827  * For the time being, let this method live just for logging the
828  * secure storage events.
829  */
830  TRACE() << "Custom event received.";
831  if (event->type() == SIGNON_SECURE_STORAGE_AVAILABLE) {
832  TRACE() << "Secure storage is available.";
833  } else if (event->type() == SIGNON_SECURE_STORAGE_NOT_AVAILABLE) {
834  TRACE() << "Secure storage still not available.";
835  }
836 
837  QObject::customEvent(event);
838 }
839 
840 void SignonSessionCore::queryUiSlot(QDBusPendingCallWatcher *call)
841 {
842  keepInUse();
843 
844  QDBusPendingReply<QVariantMap> reply = *call;
845  bool isRequestToRefresh = false;
846  Q_ASSERT_X(m_listOfRequests.size() != 0, __func__,
847  "queue of requests is empty");
848 
849  RequestData &rd = m_listOfRequests.head();
850  if (!reply.isError() && reply.count()) {
851  QVariantMap resultParameters = reply.argumentAt<0>();
852  if (resultParameters.contains(SSOUI_KEY_REFRESH)) {
853  isRequestToRefresh = true;
854  resultParameters.remove(SSOUI_KEY_REFRESH);
855  }
856 
857  rd.m_params = resultParameters;
858 
859  /* If the query ui was canceled or any other error occurred
860  * do not set this flag to true. */
861  if (resultParameters.contains(SSOUI_KEY_ERROR)
862  && (resultParameters[SSOUI_KEY_ERROR] == QUERY_ERROR_CANCELED)) {
863 
864  m_queryCredsUiDisplayed = false;
865  } else {
866  m_queryCredsUiDisplayed = true;
867  }
868  } else {
869  rd.m_params.insert(SSOUI_KEY_ERROR,
870  (int)SignOn::QUERY_ERROR_NO_SIGNONUI);
871  }
872 
873  if (!m_canceled) {
874  /* Temporary caching, if credentials are valid
875  * this data will be effectively cached */
876  m_tmpUsername = rd.m_params.value(SSO_KEY_USERNAME,
877  QVariant()).toString();
878  m_tmpPassword = rd.m_params.value(SSO_KEY_PASSWORD,
879  QVariant()).toString();
880 
881  if (isRequestToRefresh) {
882  TRACE() << "REFRESH IS REQUIRED";
883 
884  rd.m_params.remove(SSOUI_KEY_REFRESH);
885  m_plugin->processRefresh(rd.m_params);
886  } else {
887  m_plugin->processUi(rd.m_params);
888  }
889  }
890 
891  delete m_watcher;
892  m_watcher = NULL;
893 }
894 
895 void SignonSessionCore::startNewRequest()
896 {
897  keepInUse();
898 
899  m_canceled = false;
900 
901  if (m_listOfRequests.isEmpty()) {
902  TRACE() << "No more requests to process";
903  setAutoDestruct(true);
904  return;
905  }
906 
907  // there is an active request already
908  if (m_requestIsActive) {
909  TRACE() << "One request is already active";
910  return;
911  }
912 
913  //there is some UI operation with plugin
914  if (m_watcher && !m_watcher->isFinished()) {
915  TRACE() << "Some UI operation is still pending";
916  return;
917  }
918 
919  TRACE() << "Starting the authentication process";
920  setAutoDestruct(false);
921  startProcess();
922 }
923 
925 {
926  if (m_requestIsActive ||
927  m_watcher != NULL) {
928  keepInUse();
929  return;
930  }
931 
932  if (m_id)
933  sessionsOfStoredCredentials.remove(sessionName(m_id, m_method));
934  else
935  sessionsOfNonStoredCredentials.removeOne(this);
936 
937  QObjectList authSessions;
938  while (authSessions = children(), !authSessions.isEmpty()) {
939  delete authSessions.first();
940  }
941  deleteLater();
942 }
943 
945 {
946  QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
947 }
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...
QString appIdOfPeer(const QDBusConnection &peerConnection, const QDBusMessage &peerMessage)
Looks up for the application identifier of a specific client process.
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 pid_t pidOfPeer(const QDBusContext &peerContext)
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.
Contains helper functions related to Access Control.
#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)