From db3edff5d5f1c9a31f377db77d1ac4e1fa685623 Mon Sep 17 00:00:00 2001 From: Teravus Ovares Date: Sat, 5 Jan 2008 06:05:25 +0000 Subject: [PATCH] * Applying jhurliman's LLSD login enablement patch. * I'm keeping it deactivated until some issues are resolved. * I'm patching it in deactivated so the patch doesn't get outdated * I've deactivated it by commenting out the handler for the application/xml+llsd content type. * While I've tested this as much as possible on my setup and found the deactivated code doesn't cause any problems, consider this update experimental (event though it's deactivated) --- .../Framework/Communications/LoginResponse.cs | 161 +++++++++++++++++- .../Framework/Communications/LoginService.cs | 132 ++++++++++++++ .../Communications/UserManagerBase.cs | 38 ++++- OpenSim/Framework/Servers/BaseHttpServer.cs | 75 +++++++- OpenSim/Framework/Servers/LLSDMethod.cs | 33 ++++ OpenSim/Grid/UserServer/Main.cs | 3 +- OpenSim/Region/Application/OpenSimMain.cs | 1 + 7 files changed, 437 insertions(+), 6 deletions(-) create mode 100644 OpenSim/Framework/Servers/LLSDMethod.cs diff --git a/OpenSim/Framework/Communications/LoginResponse.cs b/OpenSim/Framework/Communications/LoginResponse.cs index 954aecbd43..2239a9cc49 100644 --- a/OpenSim/Framework/Communications/LoginResponse.cs +++ b/OpenSim/Framework/Communications/LoginResponse.cs @@ -30,6 +30,7 @@ using System; using System.Collections; using System.Collections.Generic; using libsecondlife; +using libsecondlife.StructuredData; using Nwc.XmlRpc; using OpenSim.Framework.Console; @@ -197,11 +198,31 @@ namespace OpenSim.Framework.UserManagement return (xmlRpcResponse); } // GenerateResponse + public LLSD GenerateFailureResponseLLSD(string reason, string message, string login) + { + LLSDMap map = new LLSDMap(); + + // Ensure Login Failed message/reason; + ErrorMessage = message; + ErrorReason = reason; + + map["reason"] = LLSD.FromString(ErrorReason); + map["message"] = LLSD.FromString(ErrorMessage); + map["login"] = LLSD.FromString(login); + + return map; + } + public XmlRpcResponse CreateFailedResponse() { return (CreateLoginFailedResponse()); } // CreateErrorConnectingToGridResponse() + public LLSD CreateFailedResponseLLSD() + { + return CreateLoginFailedResponseLLSD(); + } + public XmlRpcResponse CreateLoginFailedResponse() { return @@ -210,6 +231,14 @@ namespace OpenSim.Framework.UserManagement "false")); } // LoginFailedResponse + public LLSD CreateLoginFailedResponseLLSD() + { + return GenerateFailureResponseLLSD( + "key", + "Could not authenticate your avatar. Please check your username and password, and check the grid if problems persist.", + "false"); + } + public XmlRpcResponse CreateAlreadyLoggedInResponse() { return @@ -218,6 +247,14 @@ namespace OpenSim.Framework.UserManagement "false")); } // CreateAlreadyLoggedInResponse() + public LLSD CreateAlreadyLoggedInResponseLLSD() + { + return GenerateFailureResponseLLSD( + "presence", + "You appear to be already logged in, if this is not the case please wait for your session to timeout, if this takes longer than a few minutes please contact the grid owner", + "false"); + } + public XmlRpcResponse CreateDeadRegionResponse() { return @@ -226,6 +263,14 @@ namespace OpenSim.Framework.UserManagement "false")); } + public LLSD CreateDeadRegionResponseLLSD() + { + return GenerateFailureResponseLLSD( + "key", + "The region you are attempting to log into is not responding. Please select another region and try again.", + "false"); + } + public XmlRpcResponse CreateGridErrorResponse() { return @@ -234,6 +279,14 @@ namespace OpenSim.Framework.UserManagement "false")); } + public LLSD CreateGridErrorResponseLLSD() + { + return GenerateFailureResponseLLSD( + "key", + "Error connecting to grid. Could not percieve credentials from login XML.", + "false"); + } + #endregion public XmlRpcResponse ToXmlRpcResponse() @@ -317,6 +370,112 @@ namespace OpenSim.Framework.UserManagement } } // ToXmlRpcResponse + public LLSD ToLLSDResponse() + { + try + { + LLSDMap map = new LLSDMap(); + + map["first_name"] = LLSD.FromString(Firstname); + map["last_name"] = LLSD.FromString(Lastname); + map["agent_access"] = LLSD.FromString(agentAccess); + + map["sim_port"] = LLSD.FromInteger(SimPort); + map["sim_ip"] = LLSD.FromString(SimAddress); + + map["agent_id"] = LLSD.FromUUID(AgentID); + map["session_id"] = LLSD.FromUUID(SessionID); + map["secure_session_id"] = LLSD.FromUUID(SecureSessionID); + map["circuit_code"] = LLSD.FromInteger(CircuitCode); + map["seconds_since_epoch"] = LLSD.FromInteger((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds); + + #region Login Flags + + LLSDMap loginFlagsLLSD = new LLSDMap(); + loginFlagsLLSD["daylight_savings"] = LLSD.FromString(DST); + loginFlagsLLSD["stipend_since_login"] = LLSD.FromString(StipendSinceLogin); + loginFlagsLLSD["gendered"] = LLSD.FromString(Gendered); + loginFlagsLLSD["ever_logged_in"] = LLSD.FromString(EverLoggedIn); + map["login-flags"] = WrapLLSDMap(loginFlagsLLSD); + + #endregion Login Flags + + #region Global Textures + + LLSDMap globalTexturesLLSD = new LLSDMap(); + globalTexturesLLSD["sun_texture_id"] = LLSD.FromString(SunTexture); + globalTexturesLLSD["cloud_texture_id"] = LLSD.FromString(CloudTexture); + globalTexturesLLSD["moon_texture_id"] = LLSD.FromString(MoonTexture); + + map["global-textures"] = WrapLLSDMap(globalTexturesLLSD); + + #endregion Global Textures + + map["seed_capability"] = LLSD.FromString(seedCapability); + + // FIXME: Need a function that will convert these ArrayLists in to LLSDArrays, + // and convert the data inside them to LLSD objects as well + + //map["event_categories"] = eventCategories; + //map["event_notifications"] = new LLSDArray(); // todo + //map["classified_categories"] = classifiedCategories; + + #region UI Config + + LLSDMap uiConfigLLSD = new LLSDMap(); + uiConfigLLSD["allow_first_life"] = LLSD.FromString(allowFirstLife); + map["ui-config"] = WrapLLSDMap(uiConfigLLSD); + + #endregion UI Config + + #region Inventory + + //map["inventory-skeleton"] = agentInventory; + //map["inventory-skel-lib"] = inventoryLibrary; + //map["inventory-root"] = inventoryRoot; + //map["inventory-lib-root"] = inventoryLibRoot; + //map["inventory-lib-owner"] = inventoryLibraryOwner; + + #endregion Inventory + + map["gestures"] = new LLSDArray(); // todo + + //responseData["initial-outfit"] = initialOutfit; + //responseData["start_location"] = startLocation; + + map["seed_capability"] = LLSD.FromString(seedCapability); + map["home"] = LLSD.FromString(home); + map["look_at"] = LLSD.FromString(lookAt); + map["message"] = LLSD.FromString(welcomeMessage); + map["region_x"] = LLSD.FromInteger(RegionX * 256); + map["region_y"] = LLSD.FromInteger(RegionY * 256); + + if (m_buddyList != null) + { + //map["buddy-list"] = m_buddyList.ToArray(); + } + + map["login"] = LLSD.FromString("true"); + + return map; + } + catch (Exception e) + { + MainLog.Instance.Warn( + "CLIENT", + "LoginResponse: Error creating XML-RPC Response: " + e.Message + ); + return GenerateFailureResponseLLSD("Internal Error", "Error generating Login Response", "false"); + } + } + + private LLSDArray WrapLLSDMap(LLSDMap wrapMe) + { + LLSDArray array = new LLSDArray(); + array.Add(wrapMe); + return array; + } + public void SetEventCategories(string category, string value) { // this.eventCategoriesHash[category] = value; @@ -591,4 +750,4 @@ namespace OpenSim.Framework.UserManagement } } } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/Communications/LoginService.cs b/OpenSim/Framework/Communications/LoginService.cs index 0531d6a786..9cfac1c285 100644 --- a/OpenSim/Framework/Communications/LoginService.cs +++ b/OpenSim/Framework/Communications/LoginService.cs @@ -31,6 +31,7 @@ using System.Collections; using System.Collections.Generic; using System.Threading; using libsecondlife; +using libsecondlife.StructuredData; using Nwc.XmlRpc; using OpenSim.Framework.Communications.Cache; @@ -198,6 +199,132 @@ namespace OpenSim.Framework.UserManagement } } + public LLSD LLSDLoginMethod(LLSD request) + { + // Temporary fix + m_loginMutex.WaitOne(); + + try + { + bool GoodLogin = false; + + UserProfileData userProfile = null; + LoginResponse logResponse = new LoginResponse(); + + if (request.Type == LLSDType.Map) + { + LLSDMap map = (LLSDMap)request; + + if (map.ContainsKey("first") && map.ContainsKey("last") && map.ContainsKey("passwd")) + { + string firstname = map["first"].AsString(); + string lastname = map["last"].AsString(); + string passwd = map["passwd"].AsString(); + + userProfile = GetTheUser(firstname, lastname); + if (userProfile == null) + { + MainLog.Instance.Verbose( + "LOGIN", + "Could not find a profile for " + firstname + " " + lastname); + + return logResponse.CreateLoginFailedResponseLLSD(); + } + + GoodLogin = AuthenticateUser(userProfile, passwd); + } + } + + if (!GoodLogin) + { + return logResponse.CreateLoginFailedResponseLLSD(); + } + else + { + // If we already have a session... + if (userProfile.currentAgent != null && userProfile.currentAgent.agentOnline) + { + userProfile.currentAgent = null; + m_userManager.CommitAgent(ref userProfile); + + // Reject the login + return logResponse.CreateAlreadyLoggedInResponseLLSD(); + } + + // Otherwise... + // Create a new agent session + CreateAgent(userProfile, request); + + try + { + LLUUID agentID = userProfile.UUID; + + // Inventory Library Section + InventoryData inventData = CreateInventoryData(agentID); + ArrayList AgentInventoryArray = inventData.InventoryArray; + + Hashtable InventoryRootHash = new Hashtable(); + InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString(); + ArrayList InventoryRoot = new ArrayList(); + InventoryRoot.Add(InventoryRootHash); + userProfile.rootInventoryFolderID = inventData.RootFolderID; + + // Circuit Code + uint circode = (uint)(Util.RandomClass.Next()); + + logResponse.Lastname = userProfile.surname; + logResponse.Firstname = userProfile.username; + logResponse.AgentID = agentID.ToString(); + logResponse.SessionID = userProfile.currentAgent.sessionID.ToString(); + logResponse.SecureSessionID = userProfile.currentAgent.secureSessionID.ToString(); + logResponse.InventoryRoot = InventoryRoot; + logResponse.InventorySkeleton = AgentInventoryArray; + logResponse.InventoryLibrary = GetInventoryLibrary(); + + Hashtable InventoryLibRootHash = new Hashtable(); + InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000"; + ArrayList InventoryLibRoot = new ArrayList(); + InventoryLibRoot.Add(InventoryLibRootHash); + logResponse.InventoryLibRoot = InventoryLibRoot; + + logResponse.InventoryLibraryOwner = GetLibraryOwner(); + logResponse.CircuitCode = (Int32)circode; + //logResponse.RegionX = 0; //overwritten + //logResponse.RegionY = 0; //overwritten + logResponse.Home = "!!null temporary value {home}!!"; // Overwritten + //logResponse.LookAt = "\n[r" + TheUser.homeLookAt.X.ToString() + ",r" + TheUser.homeLookAt.Y.ToString() + ",r" + TheUser.homeLookAt.Z.ToString() + "]\n"; + //logResponse.SimAddress = "127.0.0.1"; //overwritten + //logResponse.SimPort = 0; //overwritten + logResponse.Message = GetMessage(); + logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID)); + + try + { + CustomiseResponse(logResponse, userProfile); + } + catch (Exception ex) + { + MainLog.Instance.Verbose("LOGIN", ex.ToString()); + return logResponse.CreateDeadRegionResponseLLSD(); + } + + CommitAgent(ref userProfile); + + return logResponse.ToLLSDResponse(); + } + catch (Exception ex) + { + MainLog.Instance.Verbose("LOGIN", ex.ToString()); + return logResponse.CreateFailedResponseLLSD(); + } + } + } + finally + { + m_loginMutex.ReleaseMutex(); + } + } + /// /// Customises the login response and fills in missing values. /// @@ -246,6 +373,11 @@ namespace OpenSim.Framework.UserManagement m_userManager.CreateAgent(profile, request); } + public void CreateAgent(UserProfileData profile, LLSD request) + { + m_userManager.CreateAgent(profile, request); + } + /// /// /// diff --git a/OpenSim/Framework/Communications/UserManagerBase.cs b/OpenSim/Framework/Communications/UserManagerBase.cs index 5d62e5ee47..bea56ea0e7 100644 --- a/OpenSim/Framework/Communications/UserManagerBase.cs +++ b/OpenSim/Framework/Communications/UserManagerBase.cs @@ -31,6 +31,7 @@ using System.Collections.Generic; using System.Reflection; using System.Security.Cryptography; using libsecondlife; +using libsecondlife.StructuredData; using Nwc.XmlRpc; using OpenSim.Framework.Console; @@ -394,6 +395,41 @@ namespace OpenSim.Framework.UserManagement profile.currentAgent = agent; } + public void CreateAgent(UserProfileData profile, LLSD request) + { + UserAgentData agent = new UserAgentData(); + + // User connection + agent.agentOnline = true; + + // Generate sessions + RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider(); + byte[] randDataS = new byte[16]; + byte[] randDataSS = new byte[16]; + rand.GetBytes(randDataS); + rand.GetBytes(randDataSS); + + agent.secureSessionID = new LLUUID(randDataSS, 0); + agent.sessionID = new LLUUID(randDataS, 0); + + // Profile UUID + agent.UUID = profile.UUID; + + // Current position (from Home) + agent.currentHandle = profile.homeRegion; + agent.currentPos = profile.homeLocation; + + // What time did the user login? + agent.loginTime = Util.UnixTimeSinceEpoch(); + agent.logoutTime = 0; + + // Current location + agent.regionID = LLUUID.Zero; // Fill in later + agent.currentRegion = LLUUID.Zero; // Fill in later + + profile.currentAgent = agent; + } + /// /// Saves a target agent to the database /// @@ -445,4 +481,4 @@ namespace OpenSim.Framework.UserManagement public abstract UserProfileData SetupMasterUser(string firstName, string lastName, string password); public abstract UserProfileData SetupMasterUser(LLUUID uuid); } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs index af2b27c9bc..b36cc8a7b1 100644 --- a/OpenSim/Framework/Servers/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/BaseHttpServer.cs @@ -34,6 +34,7 @@ using System.Text; using System.Threading; using System.Xml; using Nwc.XmlRpc; +using libsecondlife.StructuredData; using OpenSim.Framework.Console; namespace OpenSim.Framework.Servers @@ -43,6 +44,7 @@ namespace OpenSim.Framework.Servers protected Thread m_workerThread; protected HttpListener m_httpListener; protected Dictionary m_rpcHandlers = new Dictionary(); + protected LLSDMethod m_llsdHandler = null; protected Dictionary m_streamHandlers = new Dictionary(); protected uint m_port; protected bool m_ssl = false; @@ -90,6 +92,11 @@ namespace OpenSim.Framework.Servers return false; } + public bool SetLLSDHandler(LLSDMethod handler) + { + m_llsdHandler = handler; + return true; + } public virtual void HandleRequest(Object stateinfo) { @@ -136,7 +143,17 @@ namespace OpenSim.Framework.Servers } else { - HandleXmlRpcRequests(request, response); + switch (request.ContentType) + { + //case "application/xml+llsd": + //HandleLLSDRequests(request, response); + //break; + case "text/xml": + case "application/xml": + default: + HandleXmlRpcRequests(request, response); + break; + } } } @@ -242,7 +259,7 @@ namespace OpenSim.Framework.Servers } } - response.AddHeader("Content-type", "text/xml"); + response.ContentType = "text/xml"; byte[] buffer = Encoding.UTF8.GetBytes(responseString); @@ -263,6 +280,58 @@ namespace OpenSim.Framework.Servers } } + private void HandleLLSDRequests(HttpListenerRequest request, HttpListenerResponse response) + { + Stream requestStream = request.InputStream; + + Encoding encoding = Encoding.UTF8; + StreamReader reader = new StreamReader(requestStream, encoding); + + string requestBody = reader.ReadToEnd(); + reader.Close(); + requestStream.Close(); + + LLSD llsdRequest = null; + LLSD llsdResponse = null; + + try { llsdRequest = LLSDParser.DeserializeXml(requestBody); } + catch (Exception ex) { MainLog.Instance.Warn("HTTPD", "Error - " + ex.Message); } + + if (llsdRequest != null && m_llsdHandler != null) + { + llsdResponse = m_llsdHandler(llsdRequest); + } + else + { + LLSDMap map = new LLSDMap(); + map["reason"] = LLSD.FromString("LLSDRequest"); + map["message"] = LLSD.FromString("No handler registered for LLSD Requests"); + map["login"] = LLSD.FromString("false"); + llsdResponse = map; + } + + response.ContentType = "application/xml+llsd"; + + byte[] buffer = LLSDParser.SerializeXmlBytes(llsdResponse); + + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) + { + MainLog.Instance.Warn("HTTPD", "Error - " + ex.Message); + } + finally + { + response.OutputStream.Close(); + } + } + public void HandleHTTPRequest(Hashtable keysvals, HttpListenerRequest request, HttpListenerResponse response) { // This is a test. There's a workable alternative.. as this way sucks. @@ -436,4 +505,4 @@ namespace OpenSim.Framework.Servers m_streamHandlers.Remove(GetHandlerKey(httpMethod, path)); } } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/Servers/LLSDMethod.cs b/OpenSim/Framework/Servers/LLSDMethod.cs new file mode 100644 index 0000000000..5cd225b535 --- /dev/null +++ b/OpenSim/Framework/Servers/LLSDMethod.cs @@ -0,0 +1,33 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ +using libsecondlife.StructuredData; + +namespace OpenSim.Framework.Servers +{ + public delegate LLSD LLSDMethod(LLSD request); +} diff --git a/OpenSim/Grid/UserServer/Main.cs b/OpenSim/Grid/UserServer/Main.cs index 4645c7e885..5264870ec9 100644 --- a/OpenSim/Grid/UserServer/Main.cs +++ b/OpenSim/Grid/UserServer/Main.cs @@ -97,6 +97,7 @@ namespace OpenSim.Grid.UserServer BaseHttpServer httpServer = new BaseHttpServer(Cfg.HttpPort); httpServer.AddXmlRPCHandler("login_to_simulator", m_loginService.XmlRpcLoginMethod); + httpServer.SetLLSDHandler(m_loginService.LLSDLoginMethod); httpServer.AddXmlRPCHandler("get_user_by_name", m_userManager.XmlRPCGetUserMethodName); httpServer.AddXmlRPCHandler("get_user_by_uuid", m_userManager.XmlRPCGetUserMethodUUID); @@ -223,4 +224,4 @@ namespace OpenSim.Grid.UserServer { } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Application/OpenSimMain.cs b/OpenSim/Region/Application/OpenSimMain.cs index 0e8d71aeee..831db22ea2 100644 --- a/OpenSim/Region/Application/OpenSimMain.cs +++ b/OpenSim/Region/Application/OpenSimMain.cs @@ -312,6 +312,7 @@ namespace OpenSim m_loginService.OnLoginToRegion += backendService.AddNewSession; m_httpServer.AddXmlRPCHandler("login_to_simulator", m_loginService.XmlRpcLoginMethod); + m_httpServer.SetLLSDHandler(m_loginService.LLSDLoginMethod); if (m_standaloneAuthenticate) {