signon  8.58
signonidentity.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  * Copyright (C) 2013 Canonical Ltd.
00007  *
00008  * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com>
00009  * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
00010  * Contact: Jussi Laako <jussi.laako@linux.intel.com>
00011  *
00012  * This library is free software; you can redistribute it and/or
00013  * modify it under the terms of the GNU Lesser General Public License
00014  * version 2.1 as published by the Free Software Foundation.
00015  *
00016  * This library is distributed in the hope that it will be useful, but
00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with this library; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00024  * 02110-1301 USA
00025  */
00026 
00027 #include <iostream>
00028 #include <QVariantMap>
00029 
00030 #include "signond-common.h"
00031 #include "signonidentity.h"
00032 #include "signonui_interface.h"
00033 #include "SignOn/uisessiondata.h"
00034 #include "SignOn/uisessiondata_priv.h"
00035 #include "signoncommon.h"
00036 
00037 #include "accesscontrolmanagerhelper.h"
00038 #include "signonidentityadaptor.h"
00039 
00040 #define SIGNON_RETURN_IF_CAM_UNAVAILABLE(_ret_arg_) do {                          \
00041         if (!(CredentialsAccessManager::instance()->credentialsSystemOpened())) { \
00042             sendErrorReply(internalServerErrName, \
00043                            internalServerErrStr + \
00044                            QLatin1String("Could not access Signon Database."));\
00045             return _ret_arg_;           \
00046         }                               \
00047     } while(0)
00048 
00049 namespace SignonDaemonNS {
00050 
00051 const QString internalServerErrName = SIGNOND_INTERNAL_SERVER_ERR_NAME;
00052 const QString internalServerErrStr = SIGNOND_INTERNAL_SERVER_ERR_STR;
00053 
00054 class PendingCallWatcherWithContext: public QDBusPendingCallWatcher
00055 {
00056     Q_OBJECT
00057 
00058 public:
00059     PendingCallWatcherWithContext(const QDBusPendingCall &call,
00060                                   SignonIdentity *parent):
00061         QDBusPendingCallWatcher(call, parent),
00062         m_connection(parent->connection()),
00063         m_message(parent->message())
00064     {
00065     }
00066 
00067     PendingCallWatcherWithContext(const QDBusPendingCall &call,
00068                                   const QDBusConnection &connection,
00069                                   const QDBusMessage &message,
00070                                   SignonIdentity *parent):
00071         QDBusPendingCallWatcher(call, parent),
00072         m_connection(connection),
00073         m_message(message)
00074     {
00075     }
00076 
00077     const QDBusConnection &connection() const { return m_connection; }
00078     const QDBusMessage &message() const { return m_message; }
00079 
00080 private:
00081     QDBusConnection m_connection;
00082     QDBusMessage m_message;
00083 };
00084 
00085 SignonIdentity::SignonIdentity(quint32 id, int timeout,
00086                                SignonDaemon *parent):
00087     SignonDisposable(timeout, parent),
00088     m_pInfo(NULL)
00089 {
00090     m_id = id;
00091 
00092     (void)new SignonIdentityAdaptor(this);
00093 
00094     /*
00095      * creation of unique name for the given identity
00096      * */
00097     static quint32 incr = 0;
00098     QString objectName = SIGNOND_DAEMON_OBJECTPATH + QLatin1String("/Identity_")
00099                          + QString::number(incr++, 16);
00100     setObjectName(objectName);
00101 
00102     m_signonui = new SignonUiAdaptor(SIGNON_UI_SERVICE,
00103                                      SIGNON_UI_DAEMON_OBJECTPATH,
00104                                      QDBusConnection::sessionBus(),
00105                                      this);
00106 
00107     /* Watch for credential updates happening outside of this object (this can
00108      * happen on request of authentication plugins) */
00109     CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
00110     QObject::connect(db, SIGNAL(credentialsUpdated(quint32)),
00111                      this, SLOT(onCredentialsUpdated(quint32)));
00112 }
00113 
00114 SignonIdentity::~SignonIdentity()
00115 {
00116     emit unregistered();
00117 
00118     delete m_signonui;
00119     delete m_pInfo;
00120 }
00121 
00122 SignonIdentity *SignonIdentity::createIdentity(quint32 id, SignonDaemon *parent)
00123 {
00124     return new SignonIdentity(id, parent->identityTimeout(), parent);
00125 }
00126 
00127 void SignonIdentity::destroy()
00128 {
00129     /* Emitting the destroyed signal makes QDBusConnection unregister the
00130      * object */
00131     Q_EMIT destroyed();
00132     deleteLater();
00133 }
00134 
00135 SignonIdentityInfo SignonIdentity::queryInfo(bool &ok, bool queryPassword)
00136 {
00137     ok = true;
00138 
00139     bool needLoadFromDB = true;
00140     if (m_pInfo) {
00141         needLoadFromDB = false;
00142         if (queryPassword && m_pInfo->password().isEmpty()) {
00143             needLoadFromDB = true;
00144         }
00145     }
00146 
00147     if (needLoadFromDB) {
00148         if (m_pInfo != 0) {
00149             delete m_pInfo;
00150         }
00151 
00152         CredentialsDB *db =
00153             CredentialsAccessManager::instance()->credentialsDB();
00154         m_pInfo = new SignonIdentityInfo(db->credentials(m_id, queryPassword));
00155 
00156         if (db->lastError().isValid()) {
00157             ok = false;
00158             delete m_pInfo;
00159             m_pInfo = NULL;
00160             return SignonIdentityInfo();
00161         }
00162     }
00163 
00164     /* Make sure that we clear the password, if the caller doesn't need it */
00165     SignonIdentityInfo info = *m_pInfo;
00166     if (!queryPassword) {
00167         info.setPassword(QString());
00168     }
00169     return info;
00170 }
00171 
00172 bool SignonIdentity::addReference(const QString &reference)
00173 {
00174     TRACE() << "addReference: " << reference;
00175 
00176     SIGNON_RETURN_IF_CAM_UNAVAILABLE(false);
00177 
00178     CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
00179     if (db == NULL) {
00180         BLAME() << "NULL database handler object.";
00181         return false;
00182     }
00183     const QDBusContext &context = static_cast<QDBusContext>(*this);
00184     QString appId =
00185         AccessControlManagerHelper::instance()->appIdOfPeer(
00186                                                    context.connection(),
00187                                                    context.message());
00188     keepInUse();
00189     return db->addReference(m_id, appId, reference);
00190 }
00191 
00192 bool SignonIdentity::removeReference(const QString &reference)
00193 {
00194     TRACE() << "removeReference: " << reference;
00195 
00196     SIGNON_RETURN_IF_CAM_UNAVAILABLE(false);
00197 
00198     CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
00199     if (db == NULL) {
00200         BLAME() << "NULL database handler object.";
00201         return false;
00202     }
00203     const QDBusContext &context = static_cast<QDBusContext>(*this);
00204     QString appId =
00205         AccessControlManagerHelper::instance()->appIdOfPeer(
00206                                                    context.connection(),
00207                                                    context.message());
00208     keepInUse();
00209     return db->removeReference(m_id, appId, reference);
00210 }
00211 
00212 quint32 SignonIdentity::requestCredentialsUpdate(const QString &displayMessage)
00213 {
00214     SIGNON_RETURN_IF_CAM_UNAVAILABLE(SIGNOND_NEW_IDENTITY);
00215 
00216     bool ok;
00217     SignonIdentityInfo info = queryInfo(ok, false);
00218 
00219     if (!ok) {
00220         BLAME() << "Identity not found.";
00221         sendErrorReply(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
00222                        SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
00223         return SIGNOND_NEW_IDENTITY;
00224     }
00225     if (!info.storePassword()) {
00226         BLAME() << "Password cannot be stored.";
00227         sendErrorReply(SIGNOND_STORE_FAILED_ERR_NAME,
00228                        SIGNOND_STORE_FAILED_ERR_STR);
00229         return SIGNOND_NEW_IDENTITY;
00230     }
00231 
00232     //delay dbus reply, ui interaction might take long time to complete
00233     setDelayedReply(true);
00234 
00235     //create ui request to ask password
00236     QVariantMap uiRequest;
00237     uiRequest.insert(SSOUI_KEY_QUERYPASSWORD, true);
00238     uiRequest.insert(SSOUI_KEY_USERNAME, info.userName());
00239     uiRequest.insert(SSOUI_KEY_MESSAGE, displayMessage);
00240     uiRequest.insert(SSOUI_KEY_CAPTION, info.caption());
00241 
00242     TRACE() << "Waiting for reply from signon-ui";
00243     PendingCallWatcherWithContext *watcher =
00244         new PendingCallWatcherWithContext(m_signonui->queryDialog(uiRequest),
00245                                           this);
00246     connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
00247             this, SLOT(queryUiSlot(QDBusPendingCallWatcher*)));
00248 
00249     setAutoDestruct(false);
00250     return 0;
00251 }
00252 
00253 QVariantMap SignonIdentity::getInfo()
00254 {
00255     TRACE() << "QUERYING INFO";
00256 
00257     SIGNON_RETURN_IF_CAM_UNAVAILABLE(QVariantMap());
00258 
00259     bool ok;
00260     SignonIdentityInfo info = queryInfo(ok, false);
00261 
00262     if (!ok) {
00263         TRACE();
00264         sendErrorReply(SIGNOND_CREDENTIALS_NOT_AVAILABLE_ERR_NAME,
00265                        SIGNOND_CREDENTIALS_NOT_AVAILABLE_ERR_STR +
00266                        QLatin1String("Database querying error occurred."));
00267         return QVariantMap();
00268     }
00269 
00270     if (info.isNew()) {
00271         TRACE();
00272         sendErrorReply(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
00273                        SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
00274         return QVariantMap();
00275     }
00276 
00277     keepInUse();
00278     info.removeSecrets();
00279     return info.toMap();
00280 }
00281 
00282 void SignonIdentity::queryUserPassword(const QVariantMap &params,
00283                                        const QDBusConnection &connection,
00284                                        const QDBusMessage &message)
00285 {
00286     TRACE() << "Waiting for reply from signon-ui";
00287     PendingCallWatcherWithContext *watcher =
00288         new PendingCallWatcherWithContext(m_signonui->queryDialog(params),
00289                                           connection, message, this);
00290     connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this,
00291             SLOT(verifyUiSlot(QDBusPendingCallWatcher*)));
00292 
00293     setAutoDestruct(false);
00294 }
00295 
00296 bool SignonIdentity::verifyUser(const QVariantMap &params)
00297 {
00298     SIGNON_RETURN_IF_CAM_UNAVAILABLE(false);
00299 
00300     bool ok;
00301     SignonIdentityInfo info = queryInfo(ok, true);
00302 
00303     if (!ok) {
00304         BLAME() << "Identity not found.";
00305         sendErrorReply(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
00306                        SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
00307         return false;
00308     }
00309     if (!info.storePassword() || info.password().isEmpty()) {
00310         BLAME() << "Password is not stored.";
00311         sendErrorReply(SIGNOND_CREDENTIALS_NOT_AVAILABLE_ERR_NAME,
00312                        SIGNOND_CREDENTIALS_NOT_AVAILABLE_ERR_STR);
00313         return false;
00314     }
00315 
00316     //delay dbus reply, ui interaction might take long time to complete
00317     setDelayedReply(true);
00318 
00319     //create ui request to ask password
00320     QVariantMap uiRequest;
00321     uiRequest.unite(params);
00322     uiRequest.insert(SSOUI_KEY_QUERYPASSWORD, true);
00323     uiRequest.insert(SSOUI_KEY_USERNAME, info.userName());
00324     uiRequest.insert(SSOUI_KEY_CAPTION, info.caption());
00325 
00326     queryUserPassword(uiRequest, connection(), message());
00327     return false;
00328 }
00329 
00330 bool SignonIdentity::verifySecret(const QString &secret)
00331 {
00332     SIGNON_RETURN_IF_CAM_UNAVAILABLE(false);
00333 
00334     bool ok;
00335     queryInfo(ok);
00336     if (!ok) {
00337         TRACE();
00338         sendErrorReply(SIGNOND_CREDENTIALS_NOT_AVAILABLE_ERR_NAME,
00339                        SIGNOND_CREDENTIALS_NOT_AVAILABLE_ERR_STR +
00340                        QLatin1String("Database querying error occurred."));
00341         return false;
00342     }
00343 
00344     CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
00345     bool ret = db->checkPassword(m_pInfo->id(), m_pInfo->userName(), secret);
00346 
00347     keepInUse();
00348     return ret;
00349 }
00350 
00351 void SignonIdentity::remove()
00352 {
00353     SIGNON_RETURN_IF_CAM_UNAVAILABLE();
00354 
00355     CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
00356     if ((db == 0) || !db->removeCredentials(m_id)) {
00357         TRACE() << "Error occurred while inserting/updating credentials.";
00358         sendErrorReply(SIGNOND_REMOVE_FAILED_ERR_NAME,
00359                        SIGNOND_REMOVE_FAILED_ERR_STR +
00360                        QLatin1String("Database error occurred."));
00361         return;
00362     }
00363     setDelayedReply(true);
00364     setAutoDestruct(false);
00365     PendingCallWatcherWithContext *watcher =
00366         new PendingCallWatcherWithContext(m_signonui->removeIdentityData(m_id),
00367                                           this);
00368     connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
00369             this, SLOT(removeCompleted(QDBusPendingCallWatcher*)));
00370     keepInUse();
00371 }
00372 
00373 void SignonIdentity::removeCompleted(QDBusPendingCallWatcher *call)
00374 {
00375     Q_ASSERT(call != NULL);
00376 
00377     setAutoDestruct(true);
00378     call->deleteLater();
00379 
00380     PendingCallWatcherWithContext *context =
00381         qobject_cast<PendingCallWatcherWithContext*>(call);
00382     QDBusPendingReply<> signOnUiReply = *call;
00383     bool ok = !signOnUiReply.isError();
00384     TRACE() << (ok ? "removeIdentityData succeeded" : "removeIdentityData failed");
00385 
00386     emit infoUpdated((int)SignOn::IdentityRemoved);
00387 
00388     QDBusMessage reply = context->message().createReply();
00389     context->connection().send(reply);
00390 }
00391 
00392 bool SignonIdentity::signOut()
00393 {
00394     TRACE() << "Signout request. Identity ID: " << id();
00395     /*
00396      * - If the identity is stored (thus registered here)
00397      * signal 'sign out' to all identities subsribed to this object,
00398      * otherwise the only identity subscribed to this is the newly
00399      * created client side identity, which called this method.
00400      * - This is just a safety check, as the client identity - if it is a new
00401      * one - should not inform server side to sign out.
00402      */
00403     if (id() != SIGNOND_NEW_IDENTITY) {
00404         //clear stored sessiondata
00405         CredentialsDB *db =
00406             CredentialsAccessManager::instance()->credentialsDB();
00407         if ((db == 0) || !db->removeData(m_id)) {
00408             TRACE() << "clear data failed";
00409         }
00410 
00411         setDelayedReply(true);
00412         setAutoDestruct(false);
00413         PendingCallWatcherWithContext *watcher =
00414             new PendingCallWatcherWithContext(m_signonui->removeIdentityData(m_id),
00415                                               this);
00416         connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
00417                 this, SLOT(signOutCompleted(QDBusPendingCallWatcher*)));
00418     }
00419     keepInUse();
00420     return true;
00421 }
00422 
00423 void SignonIdentity::signOutCompleted(QDBusPendingCallWatcher *call)
00424 {
00425     Q_ASSERT(call != NULL);
00426 
00427     setAutoDestruct(true);
00428     call->deleteLater();
00429 
00430     PendingCallWatcherWithContext *context =
00431         qobject_cast<PendingCallWatcherWithContext*>(call);
00432     QDBusPendingReply<> signOnUiReply = *call;
00433     bool ok = !signOnUiReply.isError();
00434     TRACE() << (ok ? "removeIdentityData succeeded" : "removeIdentityData failed");
00435 
00436     emit infoUpdated((int)SignOn::IdentitySignedOut);
00437 
00438     QDBusMessage reply = context->message().createReply();
00439     reply << ok;
00440     context->connection().send(reply);
00441 }
00442 
00443 void SignonIdentity::onCredentialsUpdated(quint32 id)
00444 {
00445     if (id != m_id) return;
00446 
00447     TRACE() << m_id;
00448 
00449     /* Clear the cached information about the identity; some of it might not be
00450      * valid anymore */
00451     if (m_pInfo) {
00452         delete m_pInfo;
00453         m_pInfo = NULL;
00454     }
00455 
00456     emit infoUpdated((int)SignOn::IdentityDataUpdated);
00457 }
00458 
00459 quint32 SignonIdentity::store(const QVariantMap &info)
00460 {
00461     keepInUse();
00462     SIGNON_RETURN_IF_CAM_UNAVAILABLE(SIGNOND_NEW_IDENTITY);
00463 
00464     const QDBusContext &context = static_cast<QDBusContext>(*this);
00465     QString appId =
00466         AccessControlManagerHelper::instance()->appIdOfPeer(
00467                                                    context.connection(),
00468                                                    context.message());
00469 
00470     const QVariant container = info.value(SIGNOND_IDENTITY_INFO_AUTHMETHODS);
00471     MethodMap methods = container.isValid() ?
00472         qdbus_cast<MethodMap>(container.value<QDBusArgument>()) : MethodMap();
00473 
00474     if (m_pInfo == 0) {
00475         m_pInfo = new SignonIdentityInfo(info);
00476         m_pInfo->setMethods(methods);
00477         //Add creator to owner list if it has AID
00478         QStringList ownerList =
00479             info.value(SIGNOND_IDENTITY_INFO_OWNER).toStringList();
00480         if (!appId.isNull()) {
00481             ownerList.append(appId);
00482         }
00483         m_pInfo->setOwnerList(ownerList);
00484     } else {
00485         SignonIdentityInfo newInfo(info);
00486         m_pInfo->update(newInfo);
00487     }
00488 
00489     m_id = storeCredentials(*m_pInfo);
00490 
00491     if (m_id == SIGNOND_NEW_IDENTITY) {
00492         sendErrorReply(SIGNOND_STORE_FAILED_ERR_NAME,
00493                        SIGNOND_STORE_FAILED_ERR_STR);
00494     }
00495 
00496     return m_id;
00497 }
00498 
00499 quint32 SignonIdentity::storeCredentials(const SignonIdentityInfo &info)
00500 {
00501     CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
00502     if (db == NULL) {
00503         BLAME() << "NULL database handler object.";
00504         return SIGNOND_NEW_IDENTITY;
00505     }
00506 
00507     bool newIdentity = info.isNew();
00508 
00509     if (newIdentity)
00510         m_id = db->insertCredentials(info);
00511     else
00512         db->updateCredentials(info);
00513 
00514     if (db->errorOccurred()) {
00515         if (newIdentity)
00516             m_id = SIGNOND_NEW_IDENTITY;
00517 
00518         TRACE() << "Error occurred while inserting/updating credentials.";
00519     } else {
00520         if (m_pInfo) {
00521             delete m_pInfo;
00522             m_pInfo = NULL;
00523         }
00524         Q_EMIT stored(this);
00525 
00526         TRACE() << "FRESH, JUST STORED CREDENTIALS ID:" << m_id;
00527         emit infoUpdated((int)SignOn::IdentityDataUpdated);
00528     }
00529     return m_id;
00530 }
00531 
00532 void SignonIdentity::queryUiSlot(QDBusPendingCallWatcher *call)
00533 {
00534     TRACE();
00535     Q_ASSERT(call != NULL);
00536 
00537     setAutoDestruct(true);
00538 
00539     PendingCallWatcherWithContext *context =
00540         qobject_cast<PendingCallWatcherWithContext*>(call);
00541     const QDBusMessage &message = context->message();
00542     const QDBusConnection &connection = context->connection();
00543 
00544     QDBusMessage errReply;
00545     QDBusPendingReply<QVariantMap> reply = *call;
00546     call->deleteLater();
00547 
00548     QVariantMap resultParameters;
00549     if (!reply.isError() && reply.count()) {
00550         resultParameters = reply.argumentAt<0>();
00551     } else {
00552         errReply = message.createErrorReply(
00553                                   SIGNOND_IDENTITY_OPERATION_CANCELED_ERR_NAME,
00554                                   SIGNOND_IDENTITY_OPERATION_CANCELED_ERR_STR);
00555         connection.send(errReply);
00556         return;
00557     }
00558 
00559     if (!resultParameters.contains(SSOUI_KEY_ERROR)) {
00560         //no reply code
00561         errReply = message.createErrorReply(SIGNOND_INTERNAL_SERVER_ERR_NAME,
00562                                             SIGNOND_INTERNAL_SERVER_ERR_STR);
00563         connection.send(errReply);
00564         return;
00565     }
00566 
00567     int errorCode = resultParameters.value(SSOUI_KEY_ERROR).toInt();
00568     TRACE() << "error: " << errorCode;
00569     if (errorCode != QUERY_ERROR_NONE) {
00570         if (errorCode == QUERY_ERROR_CANCELED)
00571             errReply =
00572                 message.createErrorReply(
00573                                   SIGNOND_IDENTITY_OPERATION_CANCELED_ERR_NAME,
00574                                   SIGNOND_IDENTITY_OPERATION_CANCELED_ERR_STR);
00575         else
00576             errReply =
00577                 message.createErrorReply(SIGNOND_INTERNAL_SERVER_ERR_NAME,
00578                     QString(QLatin1String("signon-ui call returned error %1")).
00579                     arg(errorCode));
00580 
00581         connection.send(errReply);
00582         return;
00583     }
00584 
00585     if (resultParameters.contains(SSOUI_KEY_PASSWORD)) {
00586         CredentialsDB *db =
00587             CredentialsAccessManager::instance()->credentialsDB();
00588         if (db == NULL) {
00589             BLAME() << "NULL database handler object.";
00590             errReply = message.createErrorReply(SIGNOND_STORE_FAILED_ERR_NAME,
00591                     SIGNOND_STORE_FAILED_ERR_STR);
00592             connection.send(errReply);
00593             return;
00594         }
00595 
00596         //store new password
00597         if (m_pInfo) {
00598             m_pInfo->setPassword(resultParameters[SSOUI_KEY_PASSWORD].toString());
00599 
00600             quint32 ret = db->updateCredentials(*m_pInfo);
00601             delete m_pInfo;
00602             m_pInfo = NULL;
00603             if (ret != SIGNOND_NEW_IDENTITY) {
00604                 QDBusMessage dbusreply = message.createReply();
00605                 dbusreply << quint32(m_id);
00606                 connection.send(dbusreply);
00607                 return;
00608             } else{
00609                 BLAME() << "Error during update";
00610             }
00611         }
00612     }
00613 
00614     //this should not happen, return error
00615     errReply = message.createErrorReply(SIGNOND_INTERNAL_SERVER_ERR_NAME,
00616             SIGNOND_INTERNAL_SERVER_ERR_STR);
00617     connection.send(errReply);
00618     return;
00619 }
00620 
00621 void SignonIdentity::verifyUiSlot(QDBusPendingCallWatcher *call)
00622 {
00623     TRACE();
00624     Q_ASSERT(call != NULL);
00625 
00626     setAutoDestruct(true);
00627 
00628     PendingCallWatcherWithContext *context =
00629         qobject_cast<PendingCallWatcherWithContext*>(call);
00630     const QDBusMessage &message = context->message();
00631     const QDBusConnection &connection = context->connection();
00632 
00633     QDBusMessage errReply;
00634     QDBusPendingReply<QVariantMap> reply = *call;
00635     call->deleteLater();
00636     QVariantMap resultParameters;
00637     if (!reply.isError() && reply.count()) {
00638         resultParameters = reply.argumentAt<0>();
00639     } else {
00640         errReply =
00641             message.createErrorReply(
00642                                  SIGNOND_IDENTITY_OPERATION_CANCELED_ERR_NAME,
00643                                  SIGNOND_IDENTITY_OPERATION_CANCELED_ERR_STR);
00644         connection.send(errReply);
00645         return;
00646     }
00647 
00648     if (!resultParameters.contains(SSOUI_KEY_ERROR)) {
00649         //no reply code
00650         errReply = message.createErrorReply(SIGNOND_INTERNAL_SERVER_ERR_NAME,
00651                                             SIGNOND_INTERNAL_SERVER_ERR_STR);
00652         connection.send(errReply);
00653         return;
00654     }
00655 
00656     int errorCode = resultParameters.value(SSOUI_KEY_ERROR).toInt();
00657     TRACE() << "error: " << errorCode;
00658     if (errorCode != QUERY_ERROR_NONE) {
00659         if (errorCode == QUERY_ERROR_CANCELED)
00660             errReply = message.createErrorReply(
00661                                   SIGNOND_IDENTITY_OPERATION_CANCELED_ERR_NAME,
00662                                   SIGNOND_IDENTITY_OPERATION_CANCELED_ERR_STR);
00663         else if (errorCode == QUERY_ERROR_FORGOT_PASSWORD)
00664             errReply = message.createErrorReply(
00665                                   SIGNOND_FORGOT_PASSWORD_ERR_NAME,
00666                                   SIGNOND_FORGOT_PASSWORD_ERR_STR);
00667         else
00668             errReply = message.createErrorReply(
00669                                   SIGNOND_INTERNAL_SERVER_ERR_NAME,
00670                                   QString(QLatin1String("signon-ui call "
00671                                                         "returned error %1")).
00672                                   arg(errorCode));
00673 
00674         connection.send(errReply);
00675         return;
00676     }
00677 
00678     if (resultParameters.contains(SSOUI_KEY_PASSWORD)) {
00679         CredentialsDB *db =
00680             CredentialsAccessManager::instance()->credentialsDB();
00681         if (db == NULL) {
00682             BLAME() << "NULL database handler object.";
00683             errReply = message.createErrorReply(SIGNOND_STORE_FAILED_ERR_NAME,
00684                     SIGNOND_STORE_FAILED_ERR_STR);
00685             connection.send(errReply);
00686             return;
00687         }
00688 
00689         //compare passwords
00690         if (m_pInfo) {
00691             bool ret =
00692                 m_pInfo->password() == resultParameters[SSOUI_KEY_PASSWORD].
00693                 toString();
00694 
00695             if (!ret && resultParameters.contains(SSOUI_KEY_CONFIRMCOUNT)) {
00696                 int count = resultParameters[SSOUI_KEY_CONFIRMCOUNT].toInt();
00697                 TRACE() << "retry count:" << count;
00698                 if (count > 0) { //retry
00699                     resultParameters[SSOUI_KEY_CONFIRMCOUNT] = (count-1);
00700                     resultParameters[SSOUI_KEY_MESSAGEID] =
00701                         QUERY_MESSAGE_NOT_AUTHORIZED;
00702                     queryUserPassword(resultParameters, connection, message);
00703                     return;
00704                 } else {
00705                     //TODO show error note here if needed
00706                 }
00707             }
00708             delete m_pInfo;
00709             m_pInfo = NULL;
00710             QDBusMessage dbusreply = message.createReply();
00711             dbusreply << ret;
00712             connection.send(dbusreply);
00713             return;
00714         }
00715     }
00716     //this should not happen, return error
00717     errReply = message.createErrorReply(SIGNOND_INTERNAL_SERVER_ERR_NAME,
00718             SIGNOND_INTERNAL_SERVER_ERR_STR);
00719     connection.send(errReply);
00720     return;
00721 }
00722 
00723 } //namespace SignonDaemonNS
00724 
00725 #include "signonidentity.moc"