diff options
-rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/newview/app_settings/settings_per_account.xml | 11 | ||||
-rw-r--r-- | indra/newview/llfloatermfa.cpp | 101 | ||||
-rw-r--r-- | indra/newview/llfloatermfa.h | 50 | ||||
-rw-r--r-- | indra/newview/lllogininstance.cpp | 43 | ||||
-rw-r--r-- | indra/newview/lllogininstance.h | 1 | ||||
-rw-r--r-- | indra/newview/llstartup.cpp | 11 | ||||
-rw-r--r-- | indra/newview/llviewerfloaterreg.cpp | 2 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_mfa.xml | 49 | ||||
-rw-r--r-- | indra/newview/tests/lllogininstance_test.cpp | 1 |
10 files changed, 268 insertions, 3 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 5a06106de3..6c976e3f2d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -275,6 +275,7 @@ set(viewer_SOURCE_FILES llfloatermap.cpp llfloatermediasettings.cpp llfloatermemleak.cpp + llfloatermfa.cpp llfloatermodelpreview.cpp llfloatermodeluploadbase.cpp llfloatermyscripts.cpp @@ -918,6 +919,7 @@ set(viewer_HEADER_FILES llfloatermarketplacelistings.h llfloatermediasettings.h llfloatermemleak.h + llfloatermfa.h llfloatermodelpreview.h llfloatermodeluploadbase.h llfloatermyscripts.h diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index 537744b44c..d7d008689c 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -436,5 +436,16 @@ <key>Value</key> <integer>2</integer> </map> + <key>SLMFAHash</key> + <map> + <key>Comment</key> + <string>MFA state hash for authentication</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string></string> + </map> </map> </llsd> diff --git a/indra/newview/llfloatermfa.cpp b/indra/newview/llfloatermfa.cpp new file mode 100644 index 0000000000..7710817c23 --- /dev/null +++ b/indra/newview/llfloatermfa.cpp @@ -0,0 +1,101 @@ +/** + * @file llfloatermfa.cpp + * @brief Multi-Factor Auth token submission dialog + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloatermfa.h" + +// viewer includes +#include "llevents.h" + + +LLFloaterMFA::LLFloaterMFA(const LLSD& data) +: LLModalDialog("mfa_challenge"), + mMessage(data["message"].asStringRef()), + mReplyPumpName(data["reply_pump"].asStringRef()) +{ + +} + +LLFloaterMFA::~LLFloaterMFA() +{ +} + +BOOL LLFloaterMFA::postBuild() +{ + centerOnScreen(); + + childSetAction("continue_btn", onContinue, this); + childSetAction("cancel_btn", onCancel, this); + childSetCommitCallback("token_edit", [](LLUICtrl*, void* userdata) { onContinue(userdata);}, this); + + // this displays the prompt message + LLUICtrl *token_prompt = getChild<LLUICtrl>("token_prompt_text"); + token_prompt->setEnabled( FALSE ); + token_prompt->setValue(LLSD(mMessage)); + + LLUICtrl *token_edit = getChild<LLUICtrl>("token_edit"); + token_edit->setFocus(TRUE); + + return TRUE; +} + +// static +void LLFloaterMFA::onContinue(void* userdata ) +{ + LLFloaterMFA* self = static_cast<LLFloaterMFA*>(userdata); + + LLUICtrl *token_ctrl = self->getChild<LLUICtrl>("token_edit"); + + std::string token(token_ctrl->getValue().asStringRef()); + + if (!token.empty()) + { + LL_INFOS("MFA") << "User submits MFA token for challenge." << LL_ENDL; + if(self->mReplyPumpName != "") + { + LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(token)); + } + + self->closeFloater(); // destroys this object + } +} + +// static +void LLFloaterMFA::onCancel(void* userdata) +{ + LLFloaterMFA* self = static_cast<LLFloaterMFA*>(userdata); + LL_INFOS("MFA") << "User cancels MFA challenge attempt." << LL_ENDL; + + if(self->mReplyPumpName != "") + { + LL_DEBUGS("MFA") << self->mReplyPumpName << LL_ENDL; + LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD()); + } + + // destroys this object + self->closeFloater(); +} diff --git a/indra/newview/llfloatermfa.h b/indra/newview/llfloatermfa.h new file mode 100644 index 0000000000..9332b35877 --- /dev/null +++ b/indra/newview/llfloatermfa.h @@ -0,0 +1,50 @@ +/** + * @file llfloatermfa.h + * @brief Multi-Factor Auth token submission dialog + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERMFA_H +#define LL_LLFLOATERMFA_H + +#include "llmodaldialog.h" + + +class LLFloaterMFA : + public LLModalDialog +{ +public: + LLFloaterMFA(const LLSD& data); + virtual ~LLFloaterMFA(); + + BOOL postBuild(); + + static void onContinue(void* userdata); + static void onCancel(void* userdata); + +private: + std::string mMessage; + std::string mReplyPumpName; +}; + +#endif // LL_FLOATERMFA_H diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index e81d2cc082..902510c294 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -75,6 +75,8 @@ public: static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback"; static const char * const TOS_LISTENER_NAME = "lllogininstance_tos"; +static const char * const MFA_REPLY_PUMP = "lllogininstance_mfa_callback"; +static const char * const MFA_LISTENER_NAME = "lllogininstance_mfa"; std::string construct_start_string(); @@ -225,6 +227,8 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia request_params["id0"] = mSerialNumber; request_params["host_id"] = gSavedSettings.getString("HostID"); request_params["extended_errors"] = true; // request message_id and message_args + request_params["token"] = ""; + request_params["slmfa_hash"] = gSavedPerAccountSettings.getString("SLMFAHash"); // log request_params _before_ adding the credentials LL_DEBUGS("LLLogin") << "Login parameters: " << LLSDOStreamer<LLSDNotationFormatter>(request_params) << LL_ENDL; @@ -407,6 +411,23 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) boost::bind(&LLLoginInstance::syncWithUpdater, this, resp, _1, _2)); } } + else if(reason_response == "mfa_challenge") + { + LL_DEBUGS("LLLogin") << " MFA challenge" << LL_ENDL; + + LLSD data(LLSD::emptyMap()); + data["message"] = message_response; + data["reply_pump"] = MFA_REPLY_PUMP; + if (gViewerWindow) + { + gViewerWindow->setShowProgress(FALSE); + } + LLFloaterReg::showInstance("message_mfa", data); + LLEventPumps::instance().obtain(MFA_REPLY_PUMP) + .listen(MFA_LISTENER_NAME, [=](const LLSD& token) { + return this->handleMFAResponse(token, "token"); + }); + } else if( reason_response == "key" || reason_response == "presence" || reason_response == "connect" @@ -501,6 +522,28 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key) return true; } +bool LLLoginInstance::handleMFAResponse(const std::string& token, const std::string& key) +{ + LLEventPumps::instance().obtain(MFA_REPLY_PUMP).stopListening(MFA_LISTENER_NAME); + + if(!token.empty()) + { + LL_INFOS("LLLogin") << "LLLoginInstance::handleMFAResponse: token submitted" << LL_ENDL; + + // Set the request data to true and retry login. + mRequestData["params"][key] = token; + reconnect(); + } + else + { + LL_INFOS("LLLogin") << "LLLoginInstance::handleMFAResponse: no token, attemptComplete" << LL_ENDL; + + attemptComplete(); + } + + return true; +} + std::string construct_start_string() { std::string start; diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h index b759b43474..ce64e9e3be 100644 --- a/indra/newview/lllogininstance.h +++ b/indra/newview/lllogininstance.h @@ -84,6 +84,7 @@ private: void syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response); bool handleTOSResponse(bool v, const std::string& key); + bool handleMFAResponse(const std::string& v, const std::string& key); void attemptComplete() { mAttemptComplete = true; } // In the future an event? diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 54f3e6305c..8e81843153 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1109,10 +1109,10 @@ bool idle_startup() } else { - if (reason_response != "tos") + if (reason_response != "tos" && reason_response != "mfa_challenge") { - // Don't pop up a notification in the TOS case because - // LLFloaterTOS::onCancel() already scolded the user. + // Don't pop up a notification in the TOS or MFA cases because + // the specialized floater has already scolded the user. std::string error_code; if(response.has("errorcode")) { @@ -3597,6 +3597,11 @@ bool process_login_success_response() LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); } + if(response.has("slmfa_hash")) + { + gSavedPerAccountSettings.setString("SLMFAHash", response["slmfa_hash"]); + } + bool success = false; // JC: gesture loading done below, when we have an asset system // in place. Don't delete/clear gUserCredentials until then. diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 62d73063aa..677b55e49f 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -92,6 +92,7 @@ #include "llfloatermarketplacelistings.h" #include "llfloatermediasettings.h" #include "llfloatermemleak.h" +#include "llfloatermfa.h" #include "llfloatermodelpreview.h" #include "llfloatermyscripts.h" #include "llfloatermyenvironment.h" @@ -288,6 +289,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceValidation>); LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); + LLFloaterReg::add("message_mfa", "floater_mfa.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMFA>); LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMove>); LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGetBlockedObjectName>); LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>); diff --git a/indra/newview/skins/default/xui/en/floater_mfa.xml b/indra/newview/skins/default/xui/en/floater_mfa.xml new file mode 100644 index 0000000000..a649cc6d47 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_mfa.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + title="MFA Token Requred" + legacy_header_height="18" + can_minimize="false" + can_close="false" + height="110" + layout="topleft" + name="mfa_challenge" + help_topic="mfa_challenge" + width="550"> + <text + type="string" + word_wrap="true" + length="1" + follows="top|left" + height="15" + layout="topleft" + left="10" + name="token_prompt_text" + top="20"> + token prompt + </text> + <line_editor + follows="left|top|right" + height="19" + layout="topleft" + bottom_delta="40" + name="token_edit" + width="100" /> + <button + follows="top|left" + height="20" + label="Continue" + layout="topleft" + left="10" + name="continue_btn" + bottom_delta="30" + width="64" /> + <button + follows="top|left" + height="20" + label="Cancel" + layout="topleft" + left_pad="5" + name="cancel_btn" + bottom_delta="0" + width="64" /> +</floater> diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 8d1956957c..43f0e89222 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -190,6 +190,7 @@ std::string LLGridManager::getAppSLURLBase(const std::string& grid_name) //----------------------------------------------------------------------------- #include "../llviewercontrol.h" LLControlGroup gSavedSettings("Global"); +LLControlGroup gSavedPerAccountSettings("PerAccount"); LLControlGroup::LLControlGroup(const std::string& name) : LLInstanceTracker<LLControlGroup, std::string>(name){} |