From 646bbbc84b8010e0dacbeed5342cdb045f46cc49 Mon Sep 17 00:00:00 2001 From: MW Date: Wed, 27 Jun 2007 15:28:52 +0000 Subject: Some work on restructuring the namespaces / project names. Note this doesn't compile yet as not all the code has been changed to use the new namespaces. Am committing it now for feedback on the namespaces. --- OpenSim/Framework/UserManager/UserManagerBase.cs | 641 +++++++++++++++++++++++ 1 file changed, 641 insertions(+) create mode 100644 OpenSim/Framework/UserManager/UserManagerBase.cs (limited to 'OpenSim/Framework/UserManager/UserManagerBase.cs') diff --git a/OpenSim/Framework/UserManager/UserManagerBase.cs b/OpenSim/Framework/UserManager/UserManagerBase.cs new file mode 100644 index 0000000..eb46c14 --- /dev/null +++ b/OpenSim/Framework/UserManager/UserManagerBase.cs @@ -0,0 +1,641 @@ +/* +* Copyright (c) Contributors, http://www.openmetaverse.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 System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using OpenSim.Framework.Data; +using libsecondlife; +using System.Reflection; + +using System.Xml; +using Nwc.XmlRpc; +using OpenSim.Framework.Sims; +using OpenSim.Framework.Inventory; +using OpenSim.Framework.Utilities; + +using System.Security.Cryptography; + +namespace OpenSim.Framework.UserManagement +{ + public class UserManagerBase + { + public OpenSim.Framework.Interfaces.UserConfig _config; + Dictionary _plugins = new Dictionary(); + + /// + /// Adds a new user server plugin - user servers will be requested in the order they were loaded. + /// + /// The filename to the user server plugin DLL + public void AddPlugin(string FileName) + { + OpenSim.Framework.Console.MainLog.Instance.Verbose( "Userstorage: Attempting to load " + FileName); + Assembly pluginAssembly = Assembly.LoadFrom(FileName); + + OpenSim.Framework.Console.MainLog.Instance.Verbose( "Userstorage: Found " + pluginAssembly.GetTypes().Length + " interfaces."); + foreach (Type pluginType in pluginAssembly.GetTypes()) + { + if (!pluginType.IsAbstract) + { + Type typeInterface = pluginType.GetInterface("IUserData", true); + + if (typeInterface != null) + { + IUserData plug = (IUserData)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString())); + plug.Initialise(); + this._plugins.Add(plug.getName(), plug); + OpenSim.Framework.Console.MainLog.Instance.Verbose( "Userstorage: Added IUserData Interface"); + } + + typeInterface = null; + } + } + + pluginAssembly = null; + } + + #region Get UserProfile + /// + /// Loads a user profile from a database by UUID + /// + /// The target UUID + /// A user profile + public UserProfileData getUserProfile(LLUUID uuid) + { + foreach (KeyValuePair plugin in _plugins) + { + try + { + UserProfileData profile = plugin.Value.getUserByUUID(uuid); + profile.currentAgent = getUserAgent(profile.UUID); + return profile; + } + catch (Exception e) + { + OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")"); + } + } + + return null; + } + + + /// + /// Loads a user profile by name + /// + /// The target name + /// A user profile + public UserProfileData getUserProfile(string name) + { + foreach (KeyValuePair plugin in _plugins) + { + try + { + UserProfileData profile = plugin.Value.getUserByName(name); + profile.currentAgent = getUserAgent(profile.UUID); + return profile; + } + catch (Exception e) + { + OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")"); + } + } + + return null; + } + + /// + /// Loads a user profile by name + /// + /// First name + /// Last name + /// A user profile + public UserProfileData getUserProfile(string fname, string lname) + { + foreach (KeyValuePair plugin in _plugins) + { + try + { + UserProfileData profile = plugin.Value.getUserByName(fname,lname); + try + { + profile.currentAgent = getUserAgent(profile.UUID); + } + catch (Exception e) + { + // Ignore + } + return profile; + } + catch (Exception e) + { + OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")"); + } + } + + return null; + } + #endregion + + #region Get UserAgent + /// + /// Loads a user agent by uuid (not called directly) + /// + /// The agents UUID + /// Agent profiles + public UserAgentData getUserAgent(LLUUID uuid) + { + foreach (KeyValuePair plugin in _plugins) + { + try + { + return plugin.Value.getAgentByUUID(uuid); + } + catch (Exception e) + { + OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")"); + } + } + + return null; + } + + /// + /// Loads a user agent by name (not called directly) + /// + /// The agents name + /// A user agent + public UserAgentData getUserAgent(string name) + { + foreach (KeyValuePair plugin in _plugins) + { + try + { + return plugin.Value.getAgentByName(name); + } + catch (Exception e) + { + OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")"); + } + } + + return null; + } + + /// + /// Loads a user agent by name (not called directly) + /// + /// The agents firstname + /// The agents lastname + /// A user agent + public UserAgentData getUserAgent(string fname, string lname) + { + foreach (KeyValuePair plugin in _plugins) + { + try + { + return plugin.Value.getAgentByName(fname,lname); + } + catch (Exception e) + { + OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")"); + } + } + + return null; + } + + #endregion + + #region CreateAgent + /// + /// Creates and initialises a new user agent - make sure to use CommitAgent when done to submit to the DB + /// + /// The users profile + /// The users loginrequest + public void CreateAgent(ref UserProfileData profile, XmlRpcRequest request) + { + Hashtable requestData = (Hashtable)request.Params[0]; + + UserAgentData agent = new UserAgentData(); + + // User connection + agent.agentIP = ""; + agent.agentOnline = true; + agent.agentPort = 0; + + // 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; + + // If user specified additional start, use that + if (requestData.ContainsKey("start")) + { + string startLoc = ((string)requestData["start"]).Trim(); + if (!(startLoc == "last" || startLoc == "home")) + { + // Format: uri:Ahern&162&213&34 + try + { + string[] parts = startLoc.Remove(0, 4).Split('&'); + string region = parts[0]; + + //////////////////////////////////////////////////// + //SimProfile SimInfo = new SimProfile(); + //SimInfo = SimInfo.LoadFromGrid(theUser.currentAgent.currentHandle, _config.GridServerURL, _config.GridSendKey, _config.GridRecvKey); + } + catch (Exception e) + { + + } + } + } + + // What time did the user login? + agent.loginTime = Util.UnixTimeSinceEpoch(); + agent.logoutTime = 0; + + // Current location + agent.regionID = new LLUUID(); // Fill in later + agent.currentRegion = new LLUUID(); // Fill in later + + profile.currentAgent = agent; + } + + /// + /// Saves a target agent to the database + /// + /// The users profile + /// Successful? + public bool CommitAgent(ref UserProfileData profile) + { + // Saves the agent to database + return true; + } + + #endregion + + /// + /// Checks a user against it's password hash + /// + /// The users profile + /// The supplied password + /// Authenticated? + public virtual bool AuthenticateUser(ref UserProfileData profile, string password) + { + OpenSim.Framework.Console.MainLog.Instance.Verbose( + "Authenticating " + profile.username + " " + profile.surname); + + password = password.Remove(0, 3); //remove $1$ + + string s = Util.Md5Hash(password + ":" + profile.passwordSalt); + + return profile.passwordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase); + } + + #region Xml Response + + /// + /// + /// + /// + /// + /// + public virtual UserProfileData GetTheUser(string firstname, string lastname) + { + return getUserProfile(firstname, lastname); + } + + /// + /// + /// + /// + public virtual string GetMessage() + { + return _config.DefaultStartupMsg; + } + + /// + /// Customises the login response and fills in missing values. + /// + /// The existing response + /// The user profile + public virtual void CustomiseResponse(ref LoginResponse response, ref UserProfileData theUser) + { + + } + + /// + /// Main user login function + /// + /// The XMLRPC request + /// The response to send + public XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request) + { + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable requestData = (Hashtable)request.Params[0]; + + bool GoodXML = (requestData.Contains("first") && requestData.Contains("last") && requestData.Contains("passwd")); + bool GoodLogin = false; + string firstname = ""; + string lastname = ""; + string passwd = ""; + + UserProfileData TheUser; + LoginResponse logResponse = new LoginResponse(); + + if (GoodXML) + { + firstname = (string)requestData["first"]; + lastname = (string)requestData["last"]; + passwd = (string)requestData["passwd"]; + + TheUser = GetTheUser(firstname, lastname); + if (TheUser == null) + return logResponse.CreateLoginFailedResponse(); + + GoodLogin = AuthenticateUser(ref TheUser, passwd); + } + else + { + return logResponse.CreateGridErrorResponse(); + } + + if (!GoodLogin) + { + return logResponse.CreateLoginFailedResponse(); + } + else + { + // If we already have a session... + if (TheUser.currentAgent != null && TheUser.currentAgent.agentOnline) + { + // Reject the login + return logResponse.CreateAlreadyLoggedInResponse(); + } + // Otherwise... + // Create a new agent session + CreateAgent(ref TheUser, request); + + try + { + + LLUUID AgentID = TheUser.UUID; + + // Inventory Library Section + ArrayList AgentInventoryArray = new ArrayList(); + Hashtable TempHash; + + AgentInventory Library = new AgentInventory(); + Library.CreateRootFolder(AgentID, true); + + foreach (InventoryFolder InvFolder in Library.InventoryFolders.Values) + { + TempHash = new Hashtable(); + TempHash["name"] = InvFolder.FolderName; + TempHash["parent_id"] = InvFolder.ParentID.ToStringHyphenated(); + TempHash["version"] = (Int32)InvFolder.Version; + TempHash["type_default"] = (Int32)InvFolder.DefaultType; + TempHash["folder_id"] = InvFolder.FolderID.ToStringHyphenated(); + AgentInventoryArray.Add(TempHash); + } + + Hashtable InventoryRootHash = new Hashtable(); + InventoryRootHash["folder_id"] = Library.InventoryRoot.FolderID.ToStringHyphenated(); + ArrayList InventoryRoot = new ArrayList(); + InventoryRoot.Add(InventoryRootHash); + + // Circuit Code + uint circode = (uint)(Util.RandomClass.Next()); + + logResponse.Lastname = TheUser.surname; + logResponse.Firstname = TheUser.username; + logResponse.AgentID = AgentID.ToStringHyphenated(); + logResponse.SessionID = TheUser.currentAgent.sessionID.ToStringHyphenated(); + logResponse.SecureSessionID = TheUser.currentAgent.secureSessionID.ToStringHyphenated(); + logResponse.InventoryRoot = InventoryRoot; + logResponse.InventorySkeleton = AgentInventoryArray; + 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 = this.GetMessage(); + + try + { + this.CustomiseResponse(ref logResponse, ref TheUser); + } + catch (Exception e) + { + System.Console.WriteLine(e.ToString()); + return logResponse.CreateDeadRegionResponse(); + } + CommitAgent(ref TheUser); + + return logResponse.ToXmlRpcResponse(); + + } + catch (Exception E) + { + System.Console.WriteLine(E.ToString()); + } + //} + } + return response; + + } + + #endregion + + /// + /// Deletes an active agent session + /// + /// The request + /// The path (eg /bork/narf/test) + /// Parameters sent + /// Success "OK" else error + public string RestDeleteUserSessionMethod(string request, string path, string param) + { + // TODO! Important! + + return "OK"; + } + + /// + /// + /// + /// + public void AddUserProfile(string firstName, string lastName, string pass, uint regX, uint regY) + { + UserProfileData user = new UserProfileData(); + user.homeLocation = new LLVector3(128, 128, 100); + user.UUID = LLUUID.Random(); + user.username = firstName; + user.surname = lastName; + user.passwordHash = pass; + user.passwordSalt = ""; + user.created = Util.UnixTimeSinceEpoch(); + user.homeLookAt = new LLVector3(100, 100, 100); + user.homeRegion = Util.UIntsToLong((regX * 256), (regY * 256)); + + foreach (KeyValuePair plugin in _plugins) + { + try + { + plugin.Value.addNewUserProfile(user); + + } + catch (Exception e) + { + OpenSim.Framework.Console.MainLog.Instance.Verbose("Unable to add user via " + plugin.Key + "(" + e.ToString() + ")"); + } + } + } + + /// + /// Returns an error message that the user could not be found in the database + /// + /// XML string consisting of a error element containing individual error(s) + public string CreateUnknownUserErrorResponse() + { + System.IO.StringWriter sw = new System.IO.StringWriter(); + XmlTextWriter xw = new XmlTextWriter(sw); + + // Header + xw.Formatting = Formatting.Indented; + xw.WriteStartDocument(); + xw.WriteDocType("error", null, null, null); + xw.WriteComment("An error occured"); + xw.WriteStartElement("error"); + + // User + xw.WriteElementString("unknownuser", "Unable to find a user with that name"); + + // Footer + xw.WriteEndElement(); + xw.Flush(); + xw.Close(); + + return sw.ToString(); + } + + /// + /// Converts a user profile to an XML element which can be returned + /// + /// The user profile + /// A string containing an XML Document of the user profile + public string ProfileToXml(UserProfileData profile) + { + System.IO.StringWriter sw = new System.IO.StringWriter(); + XmlTextWriter xw = new XmlTextWriter(sw); + + // Header + xw.Formatting = Formatting.Indented; + xw.WriteStartDocument(); + xw.WriteDocType("userprofile", null, null, null); + xw.WriteComment("Found user profiles matching the request"); + xw.WriteStartElement("users"); + + // User + xw.WriteStartElement("user"); + // Account information + xw.WriteAttributeString("firstname", profile.username); + xw.WriteAttributeString("lastname", profile.surname); + xw.WriteAttributeString("uuid", profile.UUID.ToStringHyphenated()); + // Server Information + xw.WriteAttributeString("server_inventory", profile.userInventoryURI); + xw.WriteAttributeString("server_asset", profile.userAssetURI); + // Profile Information + xw.WriteAttributeString("profile_about", profile.profileAboutText); + xw.WriteAttributeString("profile_firstlife_about", profile.profileFirstText); + xw.WriteAttributeString("profile_firstlife_image", profile.profileFirstImage.ToStringHyphenated()); + xw.WriteAttributeString("profile_can_do", profile.profileCanDoMask.ToString()); + xw.WriteAttributeString("profile_want_do", profile.profileWantDoMask.ToString()); + xw.WriteAttributeString("profile_image", profile.profileImage.ToStringHyphenated()); + xw.WriteAttributeString("profile_created",profile.created.ToString()); + xw.WriteAttributeString("profile_lastlogin",profile.lastLogin.ToString()); + // Home region information + xw.WriteAttributeString("home_coordinates", profile.homeLocation.ToString()); + xw.WriteAttributeString("home_region", profile.homeRegion.ToString()); + xw.WriteAttributeString("home_look", profile.homeLookAt.ToString()); + + xw.WriteEndElement(); + + // Footer + xw.WriteEndElement(); + xw.Flush(); + xw.Close(); + + return sw.ToString(); + } + + #region REST Methods + //should most likely move out of here and into the grid's userserver sub class + public string RestGetUserMethodName(string request, string path, string param) + { + UserProfileData userProfile = getUserProfile(param.Trim()); + + if (userProfile == null) + { + return CreateUnknownUserErrorResponse(); + } + + return ProfileToXml(userProfile); + } + + public string RestGetUserMethodUUID(string request, string path, string param) + { + UserProfileData userProfile = getUserProfile(new LLUUID(param)); + + if (userProfile == null) + { + return CreateUnknownUserErrorResponse(); + } + + return ProfileToXml(userProfile); + } + #endregion + + } +} -- cgit v1.1