From 0d103a68737dcb9612c2dedeed150dc7c55e91e1 Mon Sep 17 00:00:00 2001 From: Tonya Souther Date: Mon, 22 Aug 2011 18:31:09 -0500 Subject: [PATCH] Satomi Ahn's login manager. Fixes FIRE-964. --- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llloginhandler.cpp | 54 +------- indra/newview/llloginhandler.h | 3 - indra/newview/llpanellogin.cpp | 123 +++++++++++++++++- indra/newview/llpanellogin.h | 7 + indra/newview/llsecapi.h | 16 ++- indra/newview/llsechandler_basic.cpp | 46 ++++--- indra/newview/llsechandler_basic.h | 8 +- indra/newview/llstartup.cpp | 6 +- .../skins/default/xui/en/panel_login.xml | 35 ++++- 10 files changed, 207 insertions(+), 93 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7d495ceae5..31f1985309 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13083,7 +13083,7 @@ Change of this parameter will affect the layout of buttons in notification toast Persist 1 Type - LLSD + String Value diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp index 9b4f146332..8975e30cc6 100644 --- a/indra/newview/llloginhandler.cpp +++ b/indra/newview/llloginhandler.cpp @@ -148,56 +148,4 @@ bool LLLoginHandler::handle(const LLSD& tokens, LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); } return true; -} - - - -// Initialize the credentials -// If the passed in URL contains login info, parse -// that into a credential and web login key. Otherwise -// check the command line. If the command line -// does not contain any login creds, load the last saved -// ones from the protected credential store. -// This always returns with a credential structure set in the -// login handler -LLPointer LLLoginHandler::initializeLoginInfo() -{ - LLPointer result = NULL; - // so try to load it from the UserLoginInfo - result = loadSavedUserLoginInfo(); - if (result.isNull()) - { - result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); - } - - return result; -} - - -LLPointer LLLoginHandler::loadSavedUserLoginInfo() -{ - // load the saved user login info into a LLCredential. - // perhaps this should be moved. - LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo"); - if (cmd_line_login.size() == 3) - { - - LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str()); - char md5pass[33]; /* Flawfinder: ignore */ - pass.hex_digest(md5pass); - LLSD identifier = LLSD::emptyMap(); - identifier["type"] = "agent"; - identifier["first_name"] = cmd_line_login[0]; - identifier["last_name"] = cmd_line_login[1]; - - LLSD authenticator = LLSD::emptyMap(); - authenticator["type"] = "hash"; - authenticator["algorithm"] = "md5"; - authenticator["secret"] = md5pass; - // yuck, we'll fix this with mani's changes. - gSavedSettings.setBOOL("AutoLogin", TRUE); - return gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), - identifier, authenticator); - } - return NULL; -} +} \ No newline at end of file diff --git a/indra/newview/llloginhandler.h b/indra/newview/llloginhandler.h index 1f2eacd094..0e1f17c16a 100644 --- a/indra/newview/llloginhandler.h +++ b/indra/newview/llloginhandler.h @@ -44,9 +44,6 @@ class LLLoginHandler : public LLCommandHandler // Web-based login unsupported //LLUUID getWebLoginKey() const { return mWebLoginKey; } - LLPointer loadSavedUserLoginInfo(); - LLPointer initializeLoginInfo(); - private: void parse(const LLSD& queryMap); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 0fdd6c426c..fe2ba7324e 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -167,9 +167,14 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLComboBox* server_choice_combo = sInstance->getChild("server_combo"); server_choice_combo->setCommitCallback(onSelectServer, NULL); + LLComboBox* saved_login_choice_combo = sInstance->getChild("saved_logins_combo"); + saved_login_choice_combo->setCommitCallback(onSelectSavedLogin, NULL); // server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1)); updateServerCombo(); + updateSavedLoginsCombo(); + saved_login_choice_combo->setLabel(gSavedSettings.getString("UserLoginInfo")); + childSetAction("delete_saved_login_btn", onClickDelete, this); childSetAction("connect_btn", onClickConnect, this); getChild("login")->setDefaultBtn("connect_btn"); @@ -512,7 +517,7 @@ void LLPanelLogin::getFields(LLPointer& credential, // load the credential so we can pass back the stored password or hash if the user did // not modify the password field. - credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + credential = gSecAPIHandler->loadCredential(credential_name()); LLSD identifier = LLSD::emptyMap(); LLSD authenticator = LLSD::emptyMap(); @@ -585,7 +590,7 @@ void LLPanelLogin::getFields(LLPointer& credential, } } } - credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator); + credential = gSecAPIHandler->createCredential(credential_name(), identifier, authenticator); remember = sInstance->getChild("remember_check")->getValue(); } @@ -880,6 +885,7 @@ void LLPanelLogin::onClickConnect(void *) } updateStartSLURL(); std::string username = sInstance->getChild("username_combo")->getValue().asString(); + gSavedSettings.setString("UserLoginInfo", credential_name()); LLSD blocked = FSData::allowed_login(); if (!blocked.isMap()) //hack for testing for an empty LLSD @@ -974,6 +980,23 @@ void LLPanelLogin::onClickHelp(void*) } } +//static +void LLPanelLogin::onClickDelete(void*) +{ + if (sInstance) + { + LLComboBox* saved_logins_combo = sInstance->getChild("saved_logins_combo"); + std::string credName = saved_logins_combo->getValue().asString(); + if ( credName == gSavedSettings.getString("UserLoginInfo") ) + gSavedSettings.getControl("UserLoginInfo")->resetToDefault(); + LLPointer credential = gSecAPIHandler->loadCredential(credName); + gSecAPIHandler->deleteCredential(credential); + updateSavedLoginsCombo(); + saved_logins_combo->selectFirstItem(); + saved_logins_combo->updateLabel(); + } +} + // static void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) { @@ -997,7 +1020,7 @@ void LLPanelLogin::updateServer() // for that grid and set them to the UI. if(sInstance && !sInstance->areCredentialFieldsDirty()) { - LLPointer credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + LLPointer credential = gSecAPIHandler->loadCredential(credential_name()); bool remember = sInstance->getChild("remember_check")->getValue(); sInstance->setFields(credential, remember); } @@ -1048,6 +1071,34 @@ void LLPanelLogin::updateServerCombo() update_grid_help(); } +void LLPanelLogin::updateSavedLoginsCombo() +{ + if (!sInstance) + { + return; + } + // We add all of the possible values, sorted, and then add a bar and the current value at the top + LLComboBox* saved_logins_combo = sInstance->getChild("saved_logins_combo"); + saved_logins_combo->removeall(); + + std::vector logins = gSecAPIHandler->listCredentials(); + + for (std::vector::iterator login_choice = logins.begin(); + login_choice != logins.end(); + login_choice++) + { + saved_logins_combo->add(*login_choice); + } + + saved_logins_combo->sortByName(); + +/* saved_logins_combo->addSeparator(ADD_TOP); + + saved_logins_combo->add(gSavedSettings.getString("UserLoginInfo")); + + saved_logins_combo->selectFirstItem(); */ +} + // static void LLPanelLogin::onSelectServer(LLUICtrl*, void*) { @@ -1057,7 +1108,7 @@ void LLPanelLogin::onSelectServer(LLUICtrl*, void*) LL_INFOS("AppInit") << "onSelectServer" << LL_ENDL; // The user twiddled with the grid choice ui. // apply the selection to the grid setting. - LLPointer credential; +// LLPointer credential; <- SA: is this ever used? LLComboBox* combo = sInstance->getChild("server_combo"); LLSD combo_val = combo->getSelectedValue(); @@ -1093,7 +1144,7 @@ void LLPanelLogin::onSelectServer(LLUICtrl*, void*) // combo = sInstance->getChild("start_location_combo"); - combo->setCurrentByIndex(1); +// combo->setCurrentByIndex(1); <- SA: Why??? LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation"))); @@ -1104,6 +1155,61 @@ void LLPanelLogin::onSelectServer(LLUICtrl*, void*) updateLocationCombo(false); updateLoginPanelLinks(); } + +// static +void LLPanelLogin::onSelectSavedLogin(LLUICtrl*, void*) +{ + // *NOTE: The paramters for this method are ignored. + LL_INFOS("AppInit") << "onSelectSavedLogin" << LL_ENDL; + + + LLComboBox* combo = sInstance->getChild("saved_logins_combo"); + LLSD combo_val = combo->getSelectedValue(); + if (combo_val.isUndefined()) + { + combo_val = combo->getValue(); + } + LLPointer credential = gSecAPIHandler->loadCredential(combo_val); + + combo = sInstance->getChild("start_location_combo"); + LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation"))); + + std::string credName = combo_val.asString(); + + // if they've selected another grid, we should load the credentials + // for that grid and set them to the UI. + if(sInstance && !sInstance->areCredentialFieldsDirty()) + { + LLPointer credential = gSecAPIHandler->loadCredential(credName); + bool remember = sInstance->getChild("remember_check")->getValue(); + sInstance->setFields(credential, remember); + } + U32 arobase = credName.find("@"); + if (arobase != -1 && arobase +1 < credName.length()) + credName = credName.substr(arobase+1, credName.length() - arobase - 1); +// + if(LLGridManager::getInstance()->getGrid() == credName) + { + return; + } + + try + { + LLGridManager::getInstance()->setGridChoice(credName); + } + catch (LLInvalidGridName ex) + { + // do nothing + } +// + updateServerCombo(); + // grid changed so show new splash screen (possibly) + loadLoginPage(); + updateLocationCombo(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION); + updateLocationCombo(false); + updateLoginPanelLinks(); +} + /* void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe) { @@ -1191,4 +1297,9 @@ std::string canonicalize_username(const std::string& name) return first + ' ' + last; } - +std::string LLPanelLogin::credential_name() +{ + std::string username = sInstance->getChild("username_combo")->getValue().asString(); + LLStringUtil::trim(username); + return username + "@" + LLGridManager::getInstance()->getGrid(); +} \ No newline at end of file diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index d08dcb4826..87b2581fa1 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -94,16 +94,23 @@ private: static void onClickVersion(void*); static void onClickForgotPassword(void*); static void onClickHelp(void*); + static void onClickDelete(void*); static void onPassKey(LLLineEditor* caller, void* user_data); static void onSelectServer(LLUICtrl*, void*); + static void onSelectSavedLogin(LLUICtrl*, void*); // static void onServerComboLostFocus(LLFocusableElement*); static void updateServerCombo(); + static void updateSavedLoginsCombo(); static void updateStartSLURL(); void onModeChange(const LLSD& original_value, const LLSD& new_value); void onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response); static void updateLoginPanelLinks(); + // Helper for making a standardized saved login name, depending on user name and grid name + static std::string credential_name(); + + private: LLPointer mLogoImage; boost::scoped_ptr mListener; diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index 812a539324..293012936c 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -286,7 +286,7 @@ bool operator!=(const LLCertificateVector::iterator& _lhs, const LLCertificateVe #define CRED_AUTHENTICATOR_TYPE_HASH "hash" // // LLCredential - interface for credentials providing the following functionality: -// * Persistence of credential information based on grid (for saving username/password) +// * Persistence of credential information based on some identifier/grid name (for saving username/password) // * Serialization to an OGP identifier/authenticator pair // class LLCredential : public LLRefCount @@ -295,9 +295,9 @@ public: LLCredential() {} - LLCredential(const std::string& grid) + LLCredential(const std::string& CredentialName) { - mGrid = grid; + mCredentialName = CredentialName; mIdentifier = LLSD::emptyMap(); mAuthenticator = LLSD::emptyMap(); } @@ -314,7 +314,7 @@ public: virtual LLSD getAuthenticator() { return mAuthenticator; } virtual void authenticatorType(std::string& authType); virtual LLSD getLoginParams(); - virtual std::string getGrid() { return mGrid; } + virtual std::string getCredentialName() { return mCredentialName; } virtual void clearAuthenticator() { mAuthenticator = LLSD(); } @@ -324,7 +324,7 @@ public: protected: LLSD mIdentifier; LLSD mAuthenticator; - std::string mGrid; + std::string mCredentialName; }; std::ostream& operator <<(std::ostream& s, const LLCredential& cred); @@ -464,11 +464,13 @@ public: virtual void deleteProtectedData(const std::string& data_type, const std::string& data_id)=0; - virtual LLPointer createCredential(const std::string& grid, + virtual LLPointer createCredential(const std::string& name, const LLSD& identifier, const LLSD& authenticator)=0; - virtual LLPointer loadCredential(const std::string& grid)=0; + virtual LLPointer loadCredential(const std::string& name)=0; + + virtual std::vector listCredentials()=0; virtual void saveCredential(LLPointer cred, bool save_authenticator)=0; diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 90e8ff0aae..7a301b6575 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -1445,21 +1445,21 @@ void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type, // // Create a credential object from an identifier and authenticator. credentials are -// per grid. -LLPointer LLSecAPIBasicHandler::createCredential(const std::string& grid, +// per credential name (was: grid). +LLPointer LLSecAPIBasicHandler::createCredential(const std::string& credName, const LLSD& identifier, const LLSD& authenticator) { - LLPointer result = new LLSecAPIBasicCredential(grid); + LLPointer result = new LLSecAPIBasicCredential(credName); result->setCredentialData(identifier, authenticator); return result; } -// Load a credential from the credential store, given the grid -LLPointer LLSecAPIBasicHandler::loadCredential(const std::string& grid) +// Load a credential from the credential store, given the credential name +LLPointer LLSecAPIBasicHandler::loadCredential(const std::string& credName) { - LLSD credential = getProtectedData("credential", grid); - LLPointer result = new LLSecAPIBasicCredential(grid); + LLSD credential = getProtectedData("credential", credName); + LLPointer result = new LLSecAPIBasicCredential(credName); if(credential.isMap() && credential.has("identifier")) { @@ -1512,8 +1512,8 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer cred, bool sav { credential["authenticator"] = cred->getAuthenticator(); } - LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL; - setProtectedData("credential", cred->getGrid(), credential); + LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getCredentialName() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL; + setProtectedData("credential", cred->getCredentialName(), credential); //*TODO: If we're saving Agni credentials, should we write the // credentials to the legacy password.dat/etc? _writeProtectedData(); @@ -1523,11 +1523,27 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer cred, bool sav void LLSecAPIBasicHandler::deleteCredential(LLPointer cred) { LLSD undefVal; - deleteProtectedData("credential", cred->getGrid()); + deleteProtectedData("credential", cred->getCredentialName()); cred->setCredentialData(undefVal, undefVal); _writeProtectedData(); } +// List saved logins +std::vector LLSecAPIBasicHandler::listCredentials() +{ + if (mProtectedDataMap.has("credential") && mProtectedDataMap["credential"].isMap()) + { + std::vector logins(mProtectedDataMap["credential"].size()); + int i = 0; + for (LLSD::map_const_iterator it = mProtectedDataMap["credential"].beginMap(); it != mProtectedDataMap["credential"].endMap(); ++it) + { + logins[i++] = it->first; + } + return logins; + } + else return std::vector(); +} + // load the legacy hash for agni, and decrypt it given the // mac address std::string LLSecAPIBasicHandler::_legacyLoadPassword() @@ -1562,7 +1578,7 @@ std::string LLSecAPIBasicCredential::userID() const { if (!mIdentifier.isMap()) { - return mGrid + "(null)"; + return mCredentialName + "(null)"; } else if ((std::string)mIdentifier["type"] == "agent") { @@ -1582,18 +1598,18 @@ std::string LLSecAPIBasicCredential::asString() const { if (!mIdentifier.isMap()) { - return mGrid + ":(null)"; + return mCredentialName + ":(null)"; } else if ((std::string)mIdentifier["type"] == "agent") { - return mGrid + ":" + (std::string)mIdentifier["first_name"] + " " + (std::string)mIdentifier["last_name"]; + return mCredentialName + ":" + (std::string)mIdentifier["first_name"] + " " + (std::string)mIdentifier["last_name"]; } else if ((std::string)mIdentifier["type"] == "account") { - return mGrid + ":" + (std::string)mIdentifier["account_name"]; + return mCredentialName + ":" + (std::string)mIdentifier["account_name"]; } - return mGrid + ":(unknown type)"; + return mCredentialName + ":(unknown type)"; } diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index 1ce5a87c75..5e62b8315b 100644 --- a/indra/newview/llsechandler_basic.h +++ b/indra/newview/llsechandler_basic.h @@ -208,7 +208,7 @@ public: class LLSecAPIBasicCredential : public LLCredential { public: - LLSecAPIBasicCredential(const std::string& grid) : LLCredential(grid) {} + LLSecAPIBasicCredential(const std::string& credName) : LLCredential(credName) {} virtual ~LLSecAPIBasicCredential() {} // return a value representing the user id, (could be guid, name, whatever) virtual std::string userID() const; @@ -261,15 +261,17 @@ public: // credential management routines - virtual LLPointer createCredential(const std::string& grid, + virtual LLPointer createCredential(const std::string& credName, const LLSD& identifier, const LLSD& authenticator); - virtual LLPointer loadCredential(const std::string& grid); + virtual LLPointer loadCredential(const std::string& credName); virtual void saveCredential(LLPointer cred, bool save_authenticator); virtual void deleteCredential(LLPointer cred); + + virtual std::vector listCredentials(); protected: void _readProtectedData(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 096d3db34f..31d770a661 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -790,7 +790,7 @@ bool idle_startup() // if (gUserCredential.isNull()) { - gUserCredential = gLoginHandler.initializeLoginInfo(); + gUserCredential = gSecAPIHandler->loadCredential(gSavedSettings.getString("UserLoginInfo")); } // Previous initializeLoginInfo may have generated user credentials. Re-check them. if (gUserCredential.isNull()) @@ -851,7 +851,7 @@ bool idle_startup() // show the login view until login_show() is called below. if (gUserCredential.isNull()) { - gUserCredential = gLoginHandler.initializeLoginInfo(); + gUserCredential = gSecAPIHandler->loadCredential(gSavedSettings.getString("UserLoginInfo")); } if (gHeadlessClient) { @@ -982,7 +982,6 @@ bool idle_startup() if(gUserCredential.notNull()) { userid = gUserCredential->userID(); - gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); } gSavedSettings.setBOOL("RememberPassword", gRememberPassword); LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; @@ -1297,6 +1296,7 @@ bool idle_startup() // create the default proximal channel LLVoiceChannel::initClass(); LLGridManager::getInstance()->setFavorite(); + gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); LLStartUp::setStartupState( STATE_WORLD_INIT); } else diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 279fa0b465..2857db102d 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -44,13 +44,13 @@ name="login_widgets" layout="topleft" orientation="horizontal" top="519" -width="996" +width="1246" height="80"> @@ -202,6 +202,37 @@ top_pad="0" name="server_combo" width="120" visible="false" /> + + Saved logins: + + +