signon  8.58
signonsessioncore.cpp
Go to the documentation of this file.
00001 /*
00002  * This file is part of signon
00003  *
00004  * Copyright (C) 2009-2010 Nokia Corporation.
00005  * Copyright (C) 2011 Intel Corporation.
00006  *
00007  * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
00008  * Contact: Jussi Laako <jussi.laako@linux.intel.com>
00009  *
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public License
00012  * version 2.1 as published by the Free Software Foundation.
00013  *
00014  * This library is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00022  * 02110-1301 USA
00023  */
00024 
00025 #include "signond-common.h"
00026 #include "signonauthsession.h"
00027 #include "signonidentityinfo.h"
00028 #include "signonidentity.h"
00029 #include "signonui_interface.h"
00030 #include "accesscontrolmanagerhelper.h"
00031 
00032 #include "SignOn/uisessiondata_priv.h"
00033 #include "SignOn/authpluginif.h"
00034 #include "SignOn/signonerror.h"
00035 
00036 #define MAX_IDLE_TIME SIGNOND_MAX_IDLE_TIME
00037 /*
00038  * the watchdog searches for idle sessions with period of half of idle timeout
00039  * */
00040 #define IDLE_WATCHDOG_TIMEOUT SIGNOND_MAX_IDLE_TIME * 500
00041 
00042 #define SSO_KEY_USERNAME QLatin1String("UserName")
00043 #define SSO_KEY_PASSWORD QLatin1String("Secret")
00044 #define SSO_KEY_CAPTION QLatin1String("Caption")
00045 
00046 using namespace SignonDaemonNS;
00047 
00048 /*
00049  * cache of session queues, as was mentined they cannot be static
00050  * */
00051 QMap<QString, SignonSessionCore *> sessionsOfStoredCredentials;
00052 /*
00053  * List of "zero" authsessions, needed for global signout
00054  * */
00055 QList<SignonSessionCore *> sessionsOfNonStoredCredentials;
00056 
00057 static QVariantMap filterVariantMap(const QVariantMap &other)
00058 {
00059     QVariantMap result;
00060 
00061     foreach(QString key, other.keys()) {
00062         if (!other.value(key).isNull() && other.value(key).isValid())
00063             result.insert(key, other.value(key));
00064     }
00065 
00066     return result;
00067 }
00068 
00069 static QString sessionName(const quint32 id, const QString &method)
00070 {
00071    return QString::number(id) + QLatin1String("+") + method;
00072 }
00073 
00074 SignonSessionCore::SignonSessionCore(quint32 id,
00075                                      const QString &method,
00076                                      int timeout,
00077                                      QObject *parent):
00078     SignonDisposable(timeout, parent),
00079     m_signonui(0),
00080     m_watcher(0),
00081     m_requestIsActive(false),
00082     m_canceled(false),
00083     m_id(id),
00084     m_method(method),
00085     m_queryCredsUiDisplayed(false)
00086 {
00087     m_signonui = new SignonUiAdaptor(SIGNON_UI_SERVICE,
00088                                      SIGNON_UI_DAEMON_OBJECTPATH,
00089                                      QDBusConnection::sessionBus());
00090 
00091 
00092     connect(CredentialsAccessManager::instance(),
00093             SIGNAL(credentialsSystemReady()),
00094             SLOT(credentialsSystemReady()));
00095 }
00096 
00097 SignonSessionCore::~SignonSessionCore()
00098 {
00099     delete m_plugin;
00100     delete m_watcher;
00101     delete m_signonui;
00102 
00103     m_plugin = NULL;
00104     m_signonui = NULL;
00105     m_watcher = NULL;
00106 }
00107 
00108 SignonSessionCore *SignonSessionCore::sessionCore(const quint32 id,
00109                                                   const QString &method,
00110                                                   SignonDaemon *parent)
00111 {
00112     QString key = sessionName(id, method);
00113 
00114     if (id) {
00115         if (sessionsOfStoredCredentials.contains(key)) {
00116             return sessionsOfStoredCredentials.value(key);
00117         }
00118     }
00119 
00120     SignonSessionCore *ssc = new SignonSessionCore(id, method,
00121                                                    parent->authSessionTimeout(),
00122                                                    parent);
00123 
00124     if (ssc->setupPlugin() == false) {
00125         TRACE() << "The resulted object is corrupted and has to be deleted";
00126         delete ssc;
00127         return NULL;
00128     }
00129 
00130     if (id)
00131         sessionsOfStoredCredentials.insert(key, ssc);
00132     else
00133         sessionsOfNonStoredCredentials.append(ssc);
00134 
00135     TRACE() << "The new session is created :" << key;
00136     return ssc;
00137 }
00138 
00139 quint32 SignonSessionCore::id() const
00140 {
00141     TRACE();
00142     keepInUse();
00143     return m_id;
00144 }
00145 
00146 QString SignonSessionCore::method() const
00147 {
00148     TRACE();
00149     keepInUse();
00150     return m_method;
00151 }
00152 
00153 bool SignonSessionCore::setupPlugin()
00154 {
00155     m_plugin = PluginProxy::createNewPluginProxy(m_method);
00156 
00157     if (!m_plugin) {
00158         TRACE() << "Plugin of type " << m_method << " cannot be found";
00159         return false;
00160     }
00161 
00162     connect(m_plugin,
00163             SIGNAL(processResultReply(const QVariantMap&)),
00164             this,
00165             SLOT(processResultReply(const QVariantMap&)),
00166             Qt::DirectConnection);
00167 
00168     connect(m_plugin,
00169             SIGNAL(processStore(const QVariantMap&)),
00170             this,
00171             SLOT(processStore(const QVariantMap&)),
00172             Qt::DirectConnection);
00173 
00174     connect(m_plugin,
00175             SIGNAL(processUiRequest(const QVariantMap&)),
00176             this,
00177             SLOT(processUiRequest(const QVariantMap&)),
00178             Qt::DirectConnection);
00179 
00180     connect(m_plugin,
00181             SIGNAL(processRefreshRequest(const QVariantMap&)),
00182             this,
00183             SLOT(processRefreshRequest(const QVariantMap&)),
00184             Qt::DirectConnection);
00185 
00186     connect(m_plugin,
00187             SIGNAL(processError(int, const QString&)),
00188             this,
00189             SLOT(processError(int, const QString&)),
00190             Qt::DirectConnection);
00191 
00192     connect(m_plugin,
00193             SIGNAL(stateChanged(int, const QString&)),
00194             this,
00195             SLOT(stateChangedSlot(int, const QString&)),
00196             Qt::DirectConnection);
00197 
00198     return true;
00199 }
00200 
00201 void SignonSessionCore::stopAllAuthSessions()
00202 {
00203     qDeleteAll(sessionsOfStoredCredentials);
00204     sessionsOfStoredCredentials.clear();
00205 
00206     qDeleteAll(sessionsOfNonStoredCredentials);
00207     sessionsOfNonStoredCredentials.clear();
00208 }
00209 
00210 QStringList SignonSessionCore::loadedPluginMethods(const QString &method)
00211 {
00212     foreach (SignonSessionCore *corePtr, sessionsOfStoredCredentials) {
00213         if (corePtr->method() == method)
00214             return corePtr->queryAvailableMechanisms(QStringList());
00215     }
00216 
00217     foreach (SignonSessionCore *corePtr, sessionsOfNonStoredCredentials) {
00218         if (corePtr->method() == method)
00219             return corePtr->queryAvailableMechanisms(QStringList());
00220     }
00221 
00222     return QStringList();
00223 }
00224 
00225 QStringList
00226 SignonSessionCore::queryAvailableMechanisms(const QStringList &wantedMechanisms)
00227 {
00228     keepInUse();
00229 
00230     if (!wantedMechanisms.size())
00231         return m_plugin->mechanisms();
00232 
00233     return m_plugin->mechanisms().toSet().
00234         intersect(wantedMechanisms.toSet()).toList();
00235 }
00236 
00237 void SignonSessionCore::process(const QDBusConnection &connection,
00238                                 const QDBusMessage &message,
00239                                 const QVariantMap &sessionDataVa,
00240                                 const QString &mechanism,
00241                                 const QString &cancelKey)
00242 {
00243     keepInUse();
00244     m_listOfRequests.enqueue(RequestData(connection,
00245                                          message,
00246                                          sessionDataVa,
00247                                          mechanism,
00248                                          cancelKey));
00249 
00250     if (CredentialsAccessManager::instance()->isCredentialsSystemReady())
00251         QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
00252 }
00253 
00254 void SignonSessionCore::cancel(const QString &cancelKey)
00255 {
00256     TRACE();
00257 
00258     int requestIndex;
00259     for (requestIndex = 0;
00260          requestIndex < m_listOfRequests.size();
00261          requestIndex++) {
00262         if (m_listOfRequests.at(requestIndex).m_cancelKey == cancelKey)
00263             break;
00264     }
00265 
00266     TRACE() << "The request is found with index " << requestIndex;
00267 
00268     if (requestIndex < m_listOfRequests.size()) {
00269         /* If the request being cancelled is active, we need to keep
00270          * in the queue until the plugin has replied. */
00271         bool isActive = (requestIndex == 0) && m_requestIsActive;
00272         if (isActive) {
00273             m_canceled = true;
00274             m_plugin->cancel();
00275 
00276             if (m_watcher && !m_watcher->isFinished()) {
00277                 m_signonui->cancelUiRequest(cancelKey);
00278                 delete m_watcher;
00279                 m_watcher = 0;
00280             }
00281         }
00282 
00283         /*
00284          * We must let to the m_listOfRequests to have the canceled request data
00285          * in order to delay the next request execution until the actual cancelation
00286          * will happen. We will know about that precisely: plugin must reply via
00287          * resultSlot or via errorSlot.
00288          * */
00289         RequestData rd(isActive ?
00290                        m_listOfRequests.head() :
00291                        m_listOfRequests.takeAt(requestIndex));
00292 
00293         QDBusMessage errReply =
00294             rd.m_msg.createErrorReply(SIGNOND_SESSION_CANCELED_ERR_NAME,
00295                                       SIGNOND_SESSION_CANCELED_ERR_STR);
00296         rd.m_conn.send(errReply);
00297         TRACE() << "Size of the queue is" << m_listOfRequests.size();
00298     }
00299 }
00300 
00301 void SignonSessionCore::setId(quint32 id)
00302 {
00303     keepInUse();
00304 
00305     if (m_id == id)
00306         return;
00307 
00308     QString key;
00309 
00310     if (id == 0) {
00311         key = sessionName(m_id, m_method);
00312         sessionsOfNonStoredCredentials.append(
00313                                         sessionsOfStoredCredentials.take(key));
00314     } else {
00315         key = sessionName(id, m_method);
00316         if (sessionsOfStoredCredentials.contains(key)) {
00317             qCritical() << "attempt to assign existing id";
00318             return;
00319         }
00320 
00321         sessionsOfNonStoredCredentials.removeOne(this);
00322         sessionsOfStoredCredentials[key] = this;
00323     }
00324     m_id = id;
00325 }
00326 
00327 void SignonSessionCore::startProcess()
00328 {
00329 
00330     TRACE() << "the number of requests is" << m_listOfRequests.length();
00331 
00332     m_requestIsActive = true;
00333     RequestData data = m_listOfRequests.head();
00334     QVariantMap parameters = data.m_params;
00335 
00336     /* save the client data; this should not be modified during the processing
00337      * of this request */
00338     m_clientData = parameters;
00339 
00340     if (m_id) {
00341         CredentialsDB *db =
00342             CredentialsAccessManager::instance()->credentialsDB();
00343         Q_ASSERT(db != 0);
00344 
00345         SignonIdentityInfo info = db->credentials(m_id);
00346         if (info.id() != SIGNOND_NEW_IDENTITY) {
00347             if (!parameters.contains(SSO_KEY_PASSWORD)) {
00348                 parameters[SSO_KEY_PASSWORD] = info.password();
00349             }
00350             //database overrules over sessiondata for validated username,
00351             //so that identity cannot be misused
00352             if (info.validated() || !parameters.contains(SSO_KEY_USERNAME)) {
00353                 parameters[SSO_KEY_USERNAME] = info.userName();
00354             }
00355 
00356             QStringList paramsTokenList;
00357             QStringList identityAclList = info.accessControlList();
00358 
00359             foreach(QString acl, identityAclList) {
00360                 if (AccessControlManagerHelper::instance()->
00361                     isPeerAllowedToAccess(data.m_conn, data.m_msg, acl))
00362                     paramsTokenList.append(acl);
00363             }
00364 
00365             if (!paramsTokenList.isEmpty()) {
00366                 parameters[SSO_ACCESS_CONTROL_TOKENS] = paramsTokenList;
00367             }
00368         } else {
00369             BLAME() << "Error occurred while getting data from credentials "
00370                 "database.";
00371         }
00372 
00373         QVariantMap storedParams = db->loadData(m_id, m_method);
00374 
00375         //parameters will overwrite any common keys on stored params
00376         parameters = mergeVariantMaps(storedParams, parameters);
00377     }
00378 
00379     if (parameters.contains(SSOUI_KEY_UIPOLICY)
00380         && parameters[SSOUI_KEY_UIPOLICY] == RequestPasswordPolicy) {
00381         parameters.remove(SSO_KEY_PASSWORD);
00382     }
00383 
00384     /* Temporary caching, if credentials are valid
00385      * this data will be effectively cached */
00386     m_tmpUsername = parameters[SSO_KEY_USERNAME].toString();
00387     m_tmpPassword = parameters[SSO_KEY_PASSWORD].toString();
00388 
00389     if (!m_plugin->process(parameters, data.m_mechanism)) {
00390         QDBusMessage errReply =
00391             data.m_msg.createErrorReply(SIGNOND_RUNTIME_ERR_NAME,
00392                                         SIGNOND_RUNTIME_ERR_STR);
00393         data.m_conn.send(errReply);
00394         requestDone();
00395     } else
00396         stateChangedSlot(SignOn::SessionStarted,
00397                          QLatin1String("The request is started successfully"));
00398 }
00399 
00400 void SignonSessionCore::replyError(const QDBusConnection &conn,
00401                                    const QDBusMessage &msg,
00402                                    int err, const QString &message)
00403 {
00404     keepInUse();
00405 
00406     QString errName;
00407     QString errMessage;
00408 
00409     //TODO this is needed for old error codes
00410     if( err < Error::AuthSessionErr) {
00411         BLAME() << "Deprecated error code:" << err;
00412             if (message.isEmpty())
00413                 errMessage = SIGNOND_UNKNOWN_ERR_STR;
00414             else
00415                 errMessage = message;
00416             errName = SIGNOND_UNKNOWN_ERR_NAME;
00417     }
00418 
00419     if (Error::AuthSessionErr < err && err < Error::UserErr) {
00420         switch(err) {
00421         case Error::MechanismNotAvailable:
00422             errName = SIGNOND_MECHANISM_NOT_AVAILABLE_ERR_NAME;
00423             errMessage = SIGNOND_MECHANISM_NOT_AVAILABLE_ERR_STR;
00424             break;
00425         case Error::MissingData:
00426             errName = SIGNOND_MISSING_DATA_ERR_NAME;
00427             errMessage = SIGNOND_MISSING_DATA_ERR_STR;
00428             break;
00429         case Error::InvalidCredentials:
00430             errName = SIGNOND_INVALID_CREDENTIALS_ERR_NAME;
00431             errMessage = SIGNOND_INVALID_CREDENTIALS_ERR_STR;
00432             break;
00433         case Error::NotAuthorized:
00434             errName = SIGNOND_NOT_AUTHORIZED_ERR_NAME;
00435             errMessage = SIGNOND_NOT_AUTHORIZED_ERR_STR;
00436             break;
00437         case Error::WrongState:
00438             errName = SIGNOND_WRONG_STATE_ERR_NAME;
00439             errMessage = SIGNOND_WRONG_STATE_ERR_STR;
00440             break;
00441         case Error::OperationNotSupported:
00442             errName = SIGNOND_OPERATION_NOT_SUPPORTED_ERR_NAME;
00443             errMessage = SIGNOND_OPERATION_NOT_SUPPORTED_ERR_STR;
00444             break;
00445         case Error::NoConnection:
00446             errName = SIGNOND_NO_CONNECTION_ERR_NAME;
00447             errMessage = SIGNOND_NO_CONNECTION_ERR_STR;
00448             break;
00449         case Error::Network:
00450             errName = SIGNOND_NETWORK_ERR_NAME;
00451             errMessage = SIGNOND_NETWORK_ERR_STR;
00452             break;
00453         case Error::Ssl:
00454             errName = SIGNOND_SSL_ERR_NAME;
00455             errMessage = SIGNOND_SSL_ERR_STR;
00456             break;
00457         case Error::Runtime:
00458             errName = SIGNOND_RUNTIME_ERR_NAME;
00459             errMessage = SIGNOND_RUNTIME_ERR_STR;
00460             break;
00461         case Error::SessionCanceled:
00462             errName = SIGNOND_SESSION_CANCELED_ERR_NAME;
00463             errMessage = SIGNOND_SESSION_CANCELED_ERR_STR;
00464             break;
00465         case Error::TimedOut:
00466             errName = SIGNOND_TIMED_OUT_ERR_NAME;
00467             errMessage = SIGNOND_TIMED_OUT_ERR_STR;
00468             break;
00469         case Error::UserInteraction:
00470             errName = SIGNOND_USER_INTERACTION_ERR_NAME;
00471             errMessage = SIGNOND_USER_INTERACTION_ERR_STR;
00472             break;
00473         case Error::OperationFailed:
00474             errName = SIGNOND_OPERATION_FAILED_ERR_NAME;
00475             errMessage = SIGNOND_OPERATION_FAILED_ERR_STR;
00476             break;
00477         case Error::EncryptionFailure:
00478             errName = SIGNOND_ENCRYPTION_FAILED_ERR_NAME;
00479             errMessage = SIGNOND_ENCRYPTION_FAILED_ERR_STR;
00480             break;
00481         case Error::TOSNotAccepted:
00482             errName = SIGNOND_TOS_NOT_ACCEPTED_ERR_NAME;
00483             errMessage = SIGNOND_TOS_NOT_ACCEPTED_ERR_STR;
00484             break;
00485         case Error::ForgotPassword:
00486             errName = SIGNOND_FORGOT_PASSWORD_ERR_NAME;
00487             errMessage = SIGNOND_FORGOT_PASSWORD_ERR_STR;
00488             break;
00489         case Error::IncorrectDate:
00490             errName = SIGNOND_INCORRECT_DATE_ERR_NAME;
00491             errMessage = SIGNOND_INCORRECT_DATE_ERR_STR;
00492             break;
00493         default:
00494             if (message.isEmpty())
00495                 errMessage = SIGNOND_UNKNOWN_ERR_STR;
00496             else
00497                 errMessage = message;
00498             errName = SIGNOND_UNKNOWN_ERR_NAME;
00499             break;
00500         };
00501     }
00502 
00503     if (err > Error::UserErr) {
00504         errName = SIGNOND_USER_ERROR_ERR_NAME;
00505         errMessage = (QString::fromLatin1("%1:%2")).arg(err).arg(message);
00506     }
00507 
00508     QDBusMessage errReply;
00509     errReply = msg.createErrorReply(errName,
00510                                     (message.isEmpty() ? errMessage : message));
00511     conn.send(errReply);
00512 }
00513 
00514 void SignonSessionCore::processStoreOperation(const StoreOperation &operation)
00515 {
00516     TRACE() << "Processing store operation.";
00517     CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
00518     Q_ASSERT(db != 0);
00519 
00520     if (operation.m_storeType != StoreOperation::Blob) {
00521         if (!(db->updateCredentials(operation.m_info))) {
00522             BLAME() << "Error occured while updating credentials.";
00523         }
00524     } else {
00525         TRACE() << "Processing --- StoreOperation::Blob";
00526 
00527         if (!db->storeData(m_id,
00528                            operation.m_authMethod,
00529                            operation.m_blobData)) {
00530             BLAME() << "Error occured while storing data.";
00531         }
00532     }
00533 }
00534 
00535 void SignonSessionCore::requestDone()
00536 {
00537     m_listOfRequests.removeFirst();
00538     m_requestIsActive = false;
00539     QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
00540 }
00541 
00542 void SignonSessionCore::processResultReply(const QVariantMap &data)
00543 {
00544     TRACE();
00545 
00546     keepInUse();
00547 
00548     if (m_listOfRequests.isEmpty())
00549         return;
00550 
00551     RequestData rd = m_listOfRequests.head();
00552 
00553     if (!m_canceled) {
00554         QVariantList arguments;
00555         QVariantMap filteredData = filterVariantMap(data);
00556 
00557         CredentialsAccessManager *camManager =
00558             CredentialsAccessManager::instance();
00559         CredentialsDB *db = camManager->credentialsDB();
00560         Q_ASSERT(db != 0);
00561 
00562         //update database entry
00563         if (m_id != SIGNOND_NEW_IDENTITY) {
00564             SignonIdentityInfo info = db->credentials(m_id);
00565             bool identityWasValidated = info.validated();
00566 
00567             /* update username and password from ui interaction; do not allow
00568              * updating the username if the identity is validated */
00569             if (!info.validated() && !m_tmpUsername.isEmpty()) {
00570                 info.setUserName(m_tmpUsername);
00571             }
00572             if (!m_tmpPassword.isEmpty()) {
00573                 info.setPassword(m_tmpPassword);
00574             }
00575             info.setValidated(true);
00576 
00577             StoreOperation storeOp(StoreOperation::Credentials);
00578             storeOp.m_info = info;
00579             processStoreOperation(storeOp);
00580 
00581             /* If the credentials are validated, the secrets db is not
00582              * available and not authorized keys are available, then
00583              * the store operation has been performed on the memory
00584              * cache only; inform the CAM about the situation. */
00585             if (identityWasValidated && !db->isSecretsDBOpen()) {
00586                 /* Send the storage not available event only if the curent
00587                  * result processing is following a previous signon UI query.
00588                  * This is to avoid unexpected UI pop-ups. */
00589 
00590                 if (m_queryCredsUiDisplayed) {
00591                     SecureStorageEvent *event =
00592                         new SecureStorageEvent(
00593                             (QEvent::Type)SIGNON_SECURE_STORAGE_NOT_AVAILABLE);
00594 
00595                     event->m_sender = static_cast<QObject *>(this);
00596 
00597                     QCoreApplication::postEvent(
00598                         CredentialsAccessManager::instance(),
00599                         event,
00600                         Qt::HighEventPriority);
00601                 }
00602             }
00603         }
00604 
00605         m_tmpUsername.clear();
00606         m_tmpPassword.clear();
00607 
00608         //remove secret field from output
00609         if (m_method != QLatin1String("password")
00610             && filteredData.contains(SSO_KEY_PASSWORD))
00611             filteredData.remove(SSO_KEY_PASSWORD);
00612 
00613         arguments << filteredData;
00614         rd.m_conn.send(rd.m_msg.createReply(arguments));
00615 
00616         if (m_watcher && !m_watcher->isFinished()) {
00617             m_signonui->cancelUiRequest(rd.m_cancelKey);
00618             delete m_watcher;
00619             m_watcher = 0;
00620         }
00621         m_queryCredsUiDisplayed = false;
00622     }
00623 
00624     requestDone();
00625 }
00626 
00627 void SignonSessionCore::processStore(const QVariantMap &data)
00628 {
00629     TRACE();
00630 
00631     keepInUse();
00632     if (m_id == SIGNOND_NEW_IDENTITY) {
00633         BLAME() << "Cannot store without identity";
00634         return;
00635     }
00636     QVariantMap filteredData = data;
00637     //do not store username or password
00638     filteredData.remove(SSO_KEY_PASSWORD);
00639     filteredData.remove(SSO_KEY_USERNAME);
00640     filteredData.remove(SSO_ACCESS_CONTROL_TOKENS);
00641 
00642     //store data into db
00643     CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
00644     Q_ASSERT(db != NULL);
00645 
00646     StoreOperation storeOp(StoreOperation::Blob);
00647     storeOp.m_blobData = filteredData;
00648     storeOp.m_authMethod = m_method;
00649     processStoreOperation(storeOp);
00650 
00651     /* If the credentials are validated, the secrets db is not available and
00652      * not authorized keys are available inform the CAM about the situation. */
00653     SignonIdentityInfo info = db->credentials(m_id);
00654     if (info.validated() && !db->isSecretsDBOpen()) {
00655         /* Send the storage not available event only if the curent store
00656          * processing is following a previous signon UI query. This is to avoid
00657          * unexpected UI pop-ups.
00658          */
00659         if (m_queryCredsUiDisplayed) {
00660             TRACE() << "Secure storage not available.";
00661 
00662             SecureStorageEvent *event =
00663                 new SecureStorageEvent(
00664                     (QEvent::Type)SIGNON_SECURE_STORAGE_NOT_AVAILABLE);
00665             event->m_sender = static_cast<QObject *>(this);
00666 
00667             QCoreApplication::postEvent(
00668                 CredentialsAccessManager::instance(),
00669                 event,
00670                 Qt::HighEventPriority);
00671         }
00672     }
00673 
00674     m_queryCredsUiDisplayed = false;
00675 
00676     return;
00677 }
00678 
00679 void SignonSessionCore::processUiRequest(const QVariantMap &data)
00680 {
00681     TRACE();
00682 
00683     keepInUse();
00684 
00685     if (!m_canceled && !m_listOfRequests.isEmpty()) {
00686         RequestData &request = m_listOfRequests.head();
00687         QString uiRequestId = request.m_cancelKey;
00688 
00689         if (m_watcher) {
00690             if (!m_watcher->isFinished())
00691                 m_signonui->cancelUiRequest(uiRequestId);
00692 
00693             delete m_watcher;
00694             m_watcher = 0;
00695         }
00696 
00697         request.m_params = filterVariantMap(data);
00698         request.m_params[SSOUI_KEY_REQUESTID] = uiRequestId;
00699 
00700         if (m_id == SIGNOND_NEW_IDENTITY)
00701             request.m_params[SSOUI_KEY_STORED_IDENTITY] = false;
00702         else
00703             request.m_params[SSOUI_KEY_STORED_IDENTITY] = true;
00704         request.m_params[SSOUI_KEY_IDENTITY] = m_id;
00705         request.m_params[SSOUI_KEY_CLIENT_DATA] = m_clientData;
00706         request.m_params[SSOUI_KEY_METHOD] = m_method;
00707         request.m_params[SSOUI_KEY_MECHANISM] = request.m_mechanism;
00708         /* Pass some data about the requesting client */
00709         AccessControlManagerHelper *acm =
00710             AccessControlManagerHelper::instance();
00711         request.m_params[SSOUI_KEY_PID] = acm->pidOfPeer(request.m_conn,
00712                                                          request.m_msg);
00713         request.m_params[SSOUI_KEY_APP_ID] = acm->appIdOfPeer(request.m_conn,
00714                                                               request.m_msg);
00715 
00716         CredentialsAccessManager *camManager =
00717             CredentialsAccessManager::instance();
00718         CredentialsDB *db = camManager->credentialsDB();
00719         Q_ASSERT(db != 0);
00720 
00721         //check that we have caption
00722         if (!data.contains(SSO_KEY_CAPTION)) {
00723             TRACE() << "Caption missing";
00724             if (m_id != SIGNOND_NEW_IDENTITY) {
00725                 SignonIdentityInfo info = db->credentials(m_id);
00726                 request.m_params.insert(SSO_KEY_CAPTION, info.caption());
00727                 TRACE() << "Got caption: " << info.caption();
00728             }
00729         }
00730 
00731         /*
00732          * Check the secure storage status, if any issues are encountered signal
00733          * this to the signon ui. */
00734         if (!db->isSecretsDBOpen()) {
00735             TRACE();
00736 
00737             //If there are no keys available
00738             if (!camManager->keysAvailable()) {
00739                 TRACE() << "Secrets DB not available."
00740                         << "CAM has no keys available. Informing signon-ui.";
00741                 request.m_params[SSOUI_KEY_STORAGE_KEYS_UNAVAILABLE] = true;
00742             }
00743         }
00744 
00745         m_watcher = new QDBusPendingCallWatcher(
00746                      m_signonui->queryDialog(request.m_params),
00747                      this);
00748         connect(m_watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
00749                 this, SLOT(queryUiSlot(QDBusPendingCallWatcher*)));
00750     }
00751 }
00752 
00753 void SignonSessionCore::processRefreshRequest(const QVariantMap &data)
00754 {
00755     TRACE();
00756 
00757     keepInUse();
00758 
00759     if (!m_canceled && !m_listOfRequests.isEmpty()) {
00760         QString uiRequestId = m_listOfRequests.head().m_cancelKey;
00761 
00762         if (m_watcher) {
00763             if (!m_watcher->isFinished())
00764                 m_signonui->cancelUiRequest(uiRequestId);
00765 
00766             delete m_watcher;
00767             m_watcher = 0;
00768         }
00769 
00770         m_listOfRequests.head().m_params = filterVariantMap(data);
00771         m_watcher = new QDBusPendingCallWatcher(
00772                      m_signonui->refreshDialog(m_listOfRequests.head().m_params),
00773                      this);
00774         connect(m_watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
00775                 this, SLOT(queryUiSlot(QDBusPendingCallWatcher*)));
00776     }
00777 }
00778 
00779 void SignonSessionCore::processError(int err, const QString &message)
00780 {
00781     TRACE();
00782     keepInUse();
00783     m_tmpUsername.clear();
00784     m_tmpPassword.clear();
00785 
00786     if (m_listOfRequests.isEmpty())
00787         return;
00788 
00789     RequestData rd = m_listOfRequests.head();
00790 
00791     if (!m_canceled) {
00792         replyError(rd.m_conn, rd.m_msg, err, message);
00793 
00794         if (m_watcher && !m_watcher->isFinished()) {
00795             m_signonui->cancelUiRequest(rd.m_cancelKey);
00796             delete m_watcher;
00797             m_watcher = 0;
00798         }
00799     }
00800 
00801     requestDone();
00802 }
00803 
00804 void SignonSessionCore::stateChangedSlot(int state, const QString &message)
00805 {
00806     if (!m_canceled && !m_listOfRequests.isEmpty()) {
00807         RequestData rd = m_listOfRequests.head();
00808         emit stateChanged(rd.m_cancelKey, (int)state, message);
00809     }
00810 
00811     keepInUse();
00812 }
00813 
00814 void SignonSessionCore::childEvent(QChildEvent *ce)
00815 {
00816     if (ce->added())
00817         keepInUse();
00818     else if (ce->removed())
00819         SignonDisposable::destroyUnused();
00820 }
00821 
00822 void SignonSessionCore::customEvent(QEvent *event)
00823 {
00824     /* TODO: This method is useless now, and there's probably a simpler
00825      * way to handle the secure storage events than using QEvent (such
00826      * as direct signal connections).
00827      * For the time being, let this method live just for logging the
00828      * secure storage events.
00829      */
00830     TRACE() << "Custom event received.";
00831     if (event->type() == SIGNON_SECURE_STORAGE_AVAILABLE) {
00832         TRACE() << "Secure storage is available.";
00833     } else if (event->type() == SIGNON_SECURE_STORAGE_NOT_AVAILABLE) {
00834         TRACE() << "Secure storage still not available.";
00835     }
00836 
00837     QObject::customEvent(event);
00838 }
00839 
00840 void SignonSessionCore::queryUiSlot(QDBusPendingCallWatcher *call)
00841 {
00842     keepInUse();
00843 
00844     QDBusPendingReply<QVariantMap> reply = *call;
00845     bool isRequestToRefresh = false;
00846     Q_ASSERT_X(m_listOfRequests.size() != 0, __func__,
00847                "queue of requests is empty");
00848 
00849     RequestData &rd = m_listOfRequests.head();
00850     if (!reply.isError() && reply.count()) {
00851         QVariantMap resultParameters = reply.argumentAt<0>();
00852         if (resultParameters.contains(SSOUI_KEY_REFRESH)) {
00853             isRequestToRefresh = true;
00854             resultParameters.remove(SSOUI_KEY_REFRESH);
00855         }
00856 
00857         rd.m_params = resultParameters;
00858 
00859         /* If the query ui was canceled or any other error occurred
00860          * do not set this flag to true. */
00861         if (resultParameters.contains(SSOUI_KEY_ERROR)
00862             && (resultParameters[SSOUI_KEY_ERROR] == QUERY_ERROR_CANCELED)) {
00863 
00864             m_queryCredsUiDisplayed = false;
00865         } else {
00866             m_queryCredsUiDisplayed = true;
00867         }
00868     } else {
00869         rd.m_params.insert(SSOUI_KEY_ERROR,
00870                            (int)SignOn::QUERY_ERROR_NO_SIGNONUI);
00871     }
00872 
00873     if (!m_canceled) {
00874         /* Temporary caching, if credentials are valid
00875          * this data will be effectively cached */
00876         m_tmpUsername = rd.m_params.value(SSO_KEY_USERNAME,
00877                                           QVariant()).toString();
00878         m_tmpPassword = rd.m_params.value(SSO_KEY_PASSWORD,
00879                                           QVariant()).toString();
00880 
00881         if (isRequestToRefresh) {
00882             TRACE() << "REFRESH IS REQUIRED";
00883 
00884             rd.m_params.remove(SSOUI_KEY_REFRESH);
00885             m_plugin->processRefresh(rd.m_params);
00886         } else {
00887             m_plugin->processUi(rd.m_params);
00888         }
00889     }
00890 
00891     delete m_watcher;
00892     m_watcher = NULL;
00893 }
00894 
00895 void SignonSessionCore::startNewRequest()
00896 {
00897     keepInUse();
00898 
00899     m_canceled = false;
00900 
00901     if (m_listOfRequests.isEmpty()) {
00902         TRACE() << "No more requests to process";
00903         setAutoDestruct(true);
00904         return;
00905     }
00906 
00907     // there is an active request already
00908     if (m_requestIsActive) {
00909         TRACE() << "One request is already active";
00910         return;
00911     }
00912 
00913     //there is some UI operation with plugin
00914     if (m_watcher && !m_watcher->isFinished()) {
00915         TRACE() << "Some UI operation is still pending";
00916         return;
00917     }
00918 
00919     TRACE() << "Starting the authentication process";
00920     setAutoDestruct(false);
00921     startProcess();
00922 }
00923 
00924 void SignonSessionCore::destroy()
00925 {
00926     if (m_requestIsActive ||
00927         m_watcher != NULL) {
00928         keepInUse();
00929         return;
00930     }
00931 
00932     if (m_id)
00933         sessionsOfStoredCredentials.remove(sessionName(m_id, m_method));
00934     else
00935         sessionsOfNonStoredCredentials.removeOne(this);
00936 
00937     QObjectList authSessions;
00938     while (authSessions = children(), !authSessions.isEmpty()) {
00939         delete authSessions.first();
00940     }
00941     deleteLater();
00942 }
00943 
00944 void SignonSessionCore::credentialsSystemReady()
00945 {
00946     QMetaObject::invokeMethod(this, "startNewRequest", Qt::QueuedConnection);
00947 }