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